在Spock中使用GroovyMock或类似方法模拟静态方法

ale*_*bbs 13 groovy unit-testing powermock spock powermockito

这里的第一个计时器,如果我错过任何事情,我会道歉.我希望能够使用Spock来调用静态方法.反馈会很棒

随着groovy嘲笑,我以为我能够通过静态调用,但没有找到它.作为背景,我正在改进遗留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);
   }

}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

但是如果我从ClassUnderTest运行methodUnderTest:

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
    }
}
Run Code Online (Sandbox Code Playgroud)

它抛出了一个真正的ClassWithStatic实例,它继续在其instanceMethod中失败.

Pet*_*ser 19

Spock只能模拟在Groovy中实现的静态方法.对于使用Java实现的模拟静态方法,您需要使用GroovyMock,PowerMockJMockit等工具.

PS:鉴于这些工具为实现目标而采取了一些深层技巧,我很想知道它们是否以及如何与Groovy/Spock(而不是Java/JUnit)中实现的测试一起工作.


sla*_*ron 7

以下是我如何使用 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"

   }
}
Run Code Online (Sandbox Code Playgroud)

@PowerMockIgnore注释是可选的,仅在与现有库存在冲突时才使用它