Ложный статический метод с GroovyMock или подобным в Spock
Первый таймер, извиняюсь, если что-то пропустил. Я надеюсь обойти вызов статического метода с помощью Спока. Обратная связь была бы отличной
С классными издевательствами я думал, что смогу пройти статический вызов, но не нашел его. Для справки, я нахожусь в процессе модернизации тестов в устаревшей Java. Рефакторинг запрещен. Я использую спок-0,7 с Groovy-1,8.
Вызов статического метода связан с вызовом экземпляра в этой форме:
public class ClassUnderTest{
public void methodUnderTest(Parameter param){
//everything else commented out
Thing someThing = ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(param);
}
}
staticMethod возвращает экземпляр ClassWithStatic instanceMethod возвращает Thing, необходимый в остальной части метода
Если я непосредственно использую глобальный макет, он возвращает макетированный экземпляр ok:
def exerciseTheStaticMock(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
when:
println(ClassWithStatic.staticMethodThatReturnsAnInstance().instanceMethod(testParam))
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
Но если я запускаю methodUnderTest из ClassUnderTest:
def failingAttemptToGetPastStatic(){
given:
def globalMock = GroovyMock(ClassWithStatic,global: true)
def instanceMock = Mock(ClassWithStatic)
ClassUnderTest myClassUnderTest = new ClassUnderTest()
when:
myClassUnderTest.methodUnderTest(testParam)
then:
interaction{
1 * ClassWithStatic.staticMethodThatReturnsAnInstance() >> instanceMock
1 * instanceMock.instanceMethod(_) >> returnThing
}
}
Это сбрасывает реальный экземпляр ClassWithStatic, который продолжает терпеть неудачу в его instanceMethod.
5 ответов
Спок может только высмеивать статические методы, реализованные в Groovy. Для насмешливых статических методов, реализованных в Java, вам нужно использовать такие инструменты, как GroovyMock, PowerMock или JMockit.
PS: Учитывая, что эти инструменты используют некоторые глубокие приемы для достижения своих целей, мне было бы интересно узнать, насколько хорошо они работают вместе с тестами, реализованными в Groovy/Spock (а не в Java/JUnit).
Вот как я решил мою похожую проблему (высмеивая вызов статического метода, который вызывается из другого статического класса) с помощью Spock (v1.0) и PowerMock (v1.6.4)
import org.junit.Rule
import org.powermock.core.classloader.annotations.PowerMockIgnore
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.rule.PowerMockRule
import spock.lang.Specification
import static org.powermock.api.mockito.PowerMockito.mockStatic
import static org.powermock.api.mockito.PowerMockito.when
@PrepareForTest([YourStaticClass.class])
@PowerMockIgnore(["javax.xml.*", "ch.qos.logback.*", "org.slf4j.*"])
class YourSpockSpec extends Specification {
@Rule
Powermocked powermocked = new Powermocked();
def "something something something something"() {
mockStatic(YourStaticClass.class)
when: 'something something'
def mocked = Mock(YourClass)
mocked.someMethod(_) >> "return me"
when(YourStaticClass.someStaticMethod(xyz)).thenReturn(mocked)
then: 'expect something'
YourStaticClass.someStaticMethod(xyz).someMethod(abc) == "return me"
}
}
@PowerMockIgnore
аннотация является необязательной, используйте ее только в случае возникновения конфликтов с существующими библиотеками
Обходной путь - обернуть вызов статического метода в метод экземпляра.
class BeingTested {
public void methodA() {
...
// was:
// OtherClass.staticMethod();
// replaced with:
wrapperMethod();
...
}
// add a wrapper method for testing purpose
void wrapperMethod() {
OtherClass.staticMethod();
}
}
Теперь вы можете использовать Spy для имитации статического метода.
class BeingTestedSpec extends Specification {
@Subject BeingTested object = new BeingTested()
def "test static method"() {
given: "a spy into the object"
def spyObject = Spy(object)
when: "methodA is called"
spyObject.methodA()
then: "the static method wrapper is called"
1 * spyObject.wrapperMethod() >> {}
}
}
Вы также можете заглушить стандартный ответ для метода-оболочки, если он должен возвращать значение. Это решение использует только встроенные функции Spock и работает с классами Java и Groovy без каких-либо зависимостей от PowerMock или GroovyMock.
Я недавно нашел 'spock.mockfree
', это помогает издеваться над конечными классами и статическими классами/методами. Это довольно просто, как и с этой структурой, в этом случае вам нужно будет только Spy() тестируемый класс и @MockStatic статический метод, который вам нужен.
Пример:
Мы использовали статический метод returnA класса StaticMethodClass.
public class StaticMethodClass {
public static String returnA() {
return "A";
}
}
вот код вызова
public class CallStaticMethodClass {
public String useStatic() {
return StaticMethodClass.returnA();
}
}
Теперь нам нужно протестировать метод useStatic класса CallStaticMethodClass. Но сам spock не поддерживает фиктивные статические методы, а мы поддерживаем
class CallStaticMethodClassTest extends Specification {
def 'call static method is mocked method'() {
given:
CallStaticMethodClass callStaticMethodClass = Spy()
println("useStatic")
expect:
callStaticMethodClass.useStatic() == 'M'
}
@MockStatic(StaticMethodClass)
public static String returnA() {
return "M";
}
}
Мы используем аннотацию @MockStatic, чтобы отметить, какой класс нужно имитировать. Непосредственно реализовать статический метод, который требует имитирования под ним, сигнатура метода остается прежней, но реализация отличается.
Ссылка на фреймворк:https://github.com/sayweee/spock-mockfree/blob/498e09dc95f841c4061fa8224fcaccfc53904c67/README.md
Я обошел статические методы в Groovy/Spock, создав прокси-классы, которые подставляются в реальный код. Эти прокси-классы просто возвращают статический метод, который вам нужен. Вы просто передаете прокси-классы конструктору класса, который вы тестируете.
Таким образом, когда вы пишете свои тесты, вы обращаетесь к прокси-классу (который затем возвращает статический метод), и вы сможете тестировать таким образом.