GroovyMock не работает при использовании для тестирования класса Java с вызовом статического метода

#java #unit-testing #groovy #mocking #spock

#java #модульное тестирование #groovy #издевательство #спок

Вопрос:

Groovy test не создает макет для статического класса, когда этот класс используется внутри другого класса Java. Ниже приведен фрагмент кода, который доказывает это

Тестируемый класс 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

Ответ №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.javaamp;amp;javac JavaClass.javaamp;amp;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.
Итак, я не знаю, правильно ли это использование.
Я понятия не имею, какой метод обращается к и добавляет поля staic друг к другу между Spock и Mock (JMockit).
Поэтому я создал файл журнала, чтобы проверить, вызывается ли «ClassWithStaticMethod#doSomething» из «JavaClass #method».

Комментарии:

1. ах да. вы правы… Я проверил еще раз. Приведенный выше код работает, если эти коды (JavaClass.java и ClassWithStaticMethod.java ) компилируются с помощью «groovyc».

2. возможно, ему также нужен JMockit для макета статического метода.