Моческий статический метод с GroovyMock или аналогичный в Spock

Первый таймер здесь, извинения, если я что-то пропустил. Я надеюсь получить вызов статического метода, используя Spock. Обратная связь будет отличной

С groovy mocks я думал, что смогу пройти статический звонок, но не нашел его. Для фона, я в процессе дооснащения тестов в старой Java. Рефакторинг запрещен. Я использую spock-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 возвращает Вещь, необходимую в остальной части метода

Если я непосредственно выполняю глобальный макет, он возвращает посмеянный экземпляр 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
    }
}

Но если я запустил методUnderTest из 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, который продолжает терпеть неудачу в своем методе экземпляра.

Ответ 1

Спок может только высмеивать статические методы, реализованные в Groovy. Для насмешливых статических методов, реализованных в Java, вам нужно использовать такие инструменты, как GroovyMock, PowerMock или JMockit.

PS: Учитывая, что эти инструменты используют некоторые глубокие уловки для достижения своих целей, мне было бы интересно узнать, насколько хорошо они работают вместе с тестами, реализованными в Groovy/Spock (а не в Java/JUnit).

Ответ 2

Вот как я решил свою аналогичную проблему (издевательский вызов статического метода, который вызывается из другого статического класса) с помощью 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 не является обязательной, используйте ее только при наличии конфликтов с существующими библиотеками

Ответ 3

Я обошел статические методы в Groovy/Spock, создав прокси-классы, которые подставляются в реальный код. Эти прокси-классы просто возвращают статический метод, который вам нужен. Вы просто передадите прокси-классы в конструктор класса, который вы тестируете.

Таким образом, когда вы пишете свои тесты, вы обращаетесь к прокси-классу (который затем возвращает статический метод), и вы должны иметь возможность проводить тестирование таким образом.