Имитация статического метода с помощью GroovyMock или аналогичного в Spock

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

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

Если я напрямую использую глобальный макет, он вернет фиктивный экземпляр в порядке:

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
    }
}

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


person alexgibbs    schedule 05.04.2013    source источник
comment
Если кому-то поможет, я использую GroovyMock в Spock для изменения статических методов в Java-коде, но это неправильно повлияло на другие тесты. Я использовал эту аннотацию, чтобы исправить проблему @ConfineMetaClassChanges   -  person Topera    schedule 14.10.2016
comment
См. Мой ответ на аналогичный вопрос stackoverflow.com/questions / 19493690 / using-powermock-with-spock /   -  person sweetfa    schedule 24.09.2019


Ответы (3)


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

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

person Peter Niederwieser    schedule 05.04.2013
comment
Спасибо, Питер. Попробуем интегрировать и сообщим вам - person alexgibbs; 06.04.2013
comment
Вы получили ответ? Я вижу здесь один пример: github.com/kriegaex/Spock_PowerMock - person JavaJigs; 18.07.2016

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

person slashron    schedule 27.02.2017

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

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

person Zoose    schedule 29.01.2019
comment
Вы просто должны передать прокси-классы конструктору класса, который вы тестируете. Что это означает? Статический метод не вызывается через экземпляр, поэтому нет возможности передать класс происхождения / прокси в класс тестирования. Любое дальнейшее объяснение? - person Lebecca; 11.07.2019
comment
@Lebecca, верно, но если вы создадите прокси-класс и передадите его в конструктор, вы сможете в Groovy имитировать эти прокси-классы, которые содержат статические методы. Например: `` ProxyForStaticMethod proxy = Mock (ProxyForStaticMethod); Monster monster = новый монстр (прокси); `` Теперь, когда вы пишете свои спецификации, вы можете имитировать статический метод: proxy.staticMethod() >> 'mocked static' - person Zoose; 13.07.2019
comment
Проблема здесь в том, что тестируемый класс не предназначен для создания с проксируемым классом, а с простым. Я имею в виду, что статический класс построен как утилита для удобства, для меня это не имеет смысла. Кажется, ваш метод исключает прямые вызовы статических методов в коде, верно? - person Lebecca; 15.07.2019
comment
Извините за поздний ответ. Тестируемый класс необходимо изменить, чтобы включить в него конструктор для тестирования, передав желаемые прокси-классы. Фактический код вызывает статический метод. Однако в тестовом файле вы можете предотвратить фактический статический вызов с помощью этого прокси и имитировать его, чтобы вернуть что-либо. - person Zoose; 12.08.2019