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

pu82cl6c  于 2022-11-01  发布在  其他
关注(0)|答案(5)|浏览(627)

第一次来这里,如果我错过了什么,请道歉。我希望使用Spock来绕过对静态方法的调用。反馈会很好
使用groovy mock,我以为我可以跳过静态调用,但是还没有找到它。作为背景,我正在改造遗留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的一个示例,返回方法的其余部分所需的Thing
如果我直接执行全局mock,它会返回mock示例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
    }
}

但是如果我从ClassUnderTest运行方法UnderTest:

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中继续失败。

yv5phkfx

yv5phkfx1#

Spock只能模拟Groovy中实现的静态方法。要模拟Java中实现的静态方法,您需要使用GroovyMockPowerMockJMockit等工具。
PS:考虑到这些工具为了实现它们的目标而使用了一些深层次的技巧,我很想知道它们是否能与在Groovy/Spock(而不是Java/JUnit)中实现的测试一起工作,以及工作得如何。

hs1ihplo

hs1ihplo2#

下面是我如何用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注解是可选的,仅当与现有库存在冲突时才使用

rxztt3cl

rxztt3cl3#

在Groovy/Spock中,我绕过静态方法的方法是创建代理类,并在实际代码中将其替换掉。这些代理类只返回您需要的静态方法。您只需将代理类传递给您正在测试的类的构造函数。
因此,当您编写测试时,您将接触到代理类(然后它将返回静态方法),并且您应该能够以这种方式进行测试。

zy1mlcev

zy1mlcev4#

一种解决方法是将静态方法调用 Package 到示例方法中。

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() >> {}
    }
}

如果 Package 器方法应该返回一个值,你也可以在固定的响应中为 Package 器方法设置存根。这个解决方案只使用Spock内置函数,并且可以与Java和Groovy类一起工作,而不依赖于PowerMock或GroovyMock。

hmmo2u0o

hmmo2u0o5#

我最近发现了'spock.mockfree'包,它帮助模拟final类和静态类/方法。它和这个框架一样非常简单,在这个例子中,你只需要Spy()测试下的类和@MockStatic你需要的静态方法。
示例:
我们使用了StaticMethodClass类的静态方法returnA

public class StaticMethodClass {
    public static String returnA() {
        return "A";
    }
}

这是调用代码

public class CallStaticMethodClass {
    public String useStatic() {
        return StaticMethodClass.returnA();
    }
}

现在我们需要测试CallStaticMethodClass类的useStatic方法但是spock本身并不支持mock静态方法,而我们支持

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注解来标记哪个类需要被mock直接在其下实现需要mock的静态方法,方法签名保持不变,但实现不同。
链接到框架:https://github.com/sayweee/spock-mockfree/blob/498e09dc95f841c4061fa8224fcaccfc53904c67/README.md

相关问题