#java #unit-testing #groovy #mocking #spock
#java #модульное тестирование #groovy #издевательство #спок
Вопрос:
Groovy test не создает макет для статического класса, когда этот класс используется внутри другого класса Java. Ниже приведен фрагмент кода, который доказывает это
Тестируемый класс Java:
public class JavaClass {
public void method() {
ClassWithStaticMethod.doSomething();
}
}
Класс Java со статическим методом:
public class ClassWithStaticMethod {
public static void doSomething() {
System.out.println("Static method called");
}
}
Сбой Groovy-теста:
class JavaClassTest extends Specification {
def 'test'() {
given:
GroovyMock(ClassWithStaticMethod, global: true)
JavaClass javaClass = new JavaClass()
when:
javaClass.method()
then:
1 * ClassWithStaticMethod.doSomething() // <--- FAILS
}
}
Ошибка с сообщением:
Static method called <--- original method is called, it's not mocked
Too few invocations for:
1 * ClassWithStaticMethod.doSomething() (0 invocations)
Unmatched invocations (ordered by similarity):
None
Таким образом, статический метод не издевается, и всегда вызывается фактическая реализация. Кто-нибудь может объяснить это поведение? Есть идеи, как это обойти?
Версия Java: 1.7.0_79, версия Groovy: 2.4.7, версия Spock: 1.0-groovy-2.4, cgclib: 3.1
Ответ №1:
Если java-коды компилируются с помощью groovyc
def "foo"() {
setup:
// GroovyMock(ClassWithStaticMethod, global: true)
GroovySpy(ClassWithStaticMethod, global: true)
JavaClass javaClass = new JavaClass()
when:
javaClass.method()
then:
// 1 * ClassWithStaticMethod.doSomething()
1 * ClassWithStaticMethod.doSomething() >> null
}
Если java-коды компилируются с помощью javac
1. подготовьте тестовый код (этот пример — MySpock.groovy)
// This Grabs are used for compile.
// These libraries must specifiy on class path when the file executs.
@Grapes([
@Grab(group='org.jmockit', module='jmockit', version='1.8'),
@Grab(group='org.spockframework', module='spock-core', version='1.0-groovy-2.4')
])
import spock.lang.*
import mockit.*
class MySpock extends Specification {
def "hoge"() {
setup:
// Overwrite ClassWithStaticMethod#doSomething(static method) with JMockit/MockUp
new MockUp<ClassWithStaticMethod>() {
@Mock
public static void doSomething() {
Logger.append("abc")
}
}
// Target object for this test
JavaClass javaClass = new JavaClass()
when: "Execute target method"
javaClass.method()
then: "ClassWithStaticMethod#doSomething was mocked and write the value in a file"
Logger.count() == 1
cleanup: "Delete log file for this test"
Logger.delete()
}
}
// Logging Utility for only this test.
class Logger {
static logFile = new File("/tmp/MySpock.groovy.log")
static append = {String msg -> logFile.append("${msg}${System.getProperty("line.separator")}")}
static count = {logFile.readLines()?.size()?:0}
static delete = { logFile.delete() }
}
2. скомпилируйте коды
javac ClassWithStaticMethod.javaamp;amp;javac JavaClass.javaamp;amp;groovyc MySpock.groovy
3. выполнить тест
groovy -cp .:$HOME/.groovy/grapes/org.jmockit/jmockit/jars/jmockit-1.8.jar:$HOME/.groovy/grapes/org.spockframework/spock-core/jars/spock-core-1.0-groovy-2.4.jar MySpock
Я впервые использовал JMockit.
Итак, я не знаю, правильно ли это использование.
Я понятия не имею, какой метод обращается к и добавляет поля staic друг к другу между Spock и Mock (JMockit).
Поэтому я создал файл журнала, чтобы проверить, вызывается ли «ClassWithStaticMethod#doSomething» из «JavaClass #method».
Комментарии:
1. ах да. вы правы… Я проверил еще раз. Приведенный выше код работает, если эти коды (JavaClass.java и ClassWithStaticMethod.java ) компилируются с помощью «groovyc».
2. возможно, ему также нужен JMockit для макета статического метода.