【问题标题】:GroovyMock not working when used to test Java class with static method call当用于使用静态方法调用测试 Java 类时,GroovyMock 不起作用
【发布时间】:2017-02-18 23:48:13
【问题描述】:

当静态类在其他 Java 类中使用时,Groovy 测试不会为静态类创建模拟。下面是证明这一点的代码sn-p

被测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

【问题讨论】:

    标签: java unit-testing groovy mocking spock


    【解决方案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.java&&javac JavaClass.java&&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。
    所以,我不知道这种用法是否正确。
    我不知道在 Spock 和 Mock(JMockit) 之间访问和添加静态字段的方法。
    因此我创建了日志文件来检查是否从“JavaClass#method”调用了“ClassWithStaticMethod#doSomething”。

    【讨论】:

    • 哦,是的。你是对的......我再次检查。如果这些代码(JavaClass.java 和 ClassWithStaticMethod.java)使用“groovyc”编译,则上述代码有效。
    • 静态方法的 Mock 可能也需要 JMockit。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多