Некоторые проблемы в практике модульного тестирования Spock 1

модульный тест

Когда есть несколько сценариев для тестируемого метода, как его организовать?

Общий подход таков: одному методу тестирования соответствует один метод тестирования. При наличии нескольких сцен используйтеwhen,thenблок для разделения

def "test_method"() {
    when: "用例场景1 描述"
    // do something
    then: ""
    // verify something
    /* ---------------------------------------------------------------------------- */
    
    when: "用例场景2 描述"
    // do something
    then: ""
    // verify something
}

Почему вы не можете использовать универсальные сопоставители в блоках кода when, но можете в коде then

Существующий код выглядит следующим образом:

def "test_settleBind"() {
    // BindSettleRelationReq relationReq = new BindSettleRelationReq()
    when: "request bean channelcode is blank"
    BindSettleRelationResp resp = channelService.settleBind(*_)
    then:
    resp.status == "0"
}

ОтноситсяsettleBindМетод не заботится о переданных параметрах, а значением состояния возвращаемого значения всегда является строка 0. Но при запуске выдает ошибку:

groovy.lang.MissingMethodException: No signature of method: com.fingard.rh.rhf.webapi.app.service.impl.remote.WebapiPayChannelServiceImpl.settleBind() is applicable for argument types: (org.spockframework.lang.SpreadWildcard) values: [*_]

Это означает, что параметры метода не совпадают.

Существенная причина в том, что,На данный момент фактический объект (из нового) используется в блоке when вместо Spock Mock., поэтому при использовании сопоставителя будет сообщено о несоответствии типа параметра.

Делает ли Spock однократное тестирование закрытых методов и как?

Я видел несколько статей о том, следует ли проводить модульное тестирование приватных методов.Популярный ответ таков: приватные методы не должны иметь сложной логики, просто охватывать общедоступные методы, вызывающие приватные методы. Если логика приватного метода очень сложна, то для выполнения этой части функции следует выделить отдельный класс.

You generally don't unit test private methods directly. Since they are private, consider them an implementation detail. Nobody is ever going to call one of them and expect it to work a particular way.

You should instead test your public interface. If the methods that call your private methods are working as you expect, you then assume by extension that your private methods are working correctly.

Но есть и люди, которые придерживаются противоположного мнения.Реальность такова, что логика очень сложная, но из-за иерархии классов и проблем с правами доступа (вызывается только в определенном классе) ее не следует абстрагировать отдельно.

I disagree. Sometimes a private method is just an implementation detail, but it still is complex enough that it warrants testing, to make sure it works right. The public interface may be offering a too high level of abstraction to write a test which directly targets this particular algorithm. It's not always feasible to factor it out into a separate class, for due to the shared data. In this case I'd say it's OK to test a private method

Моя точка зрения такова,Частные методы должны быть проверены, и его можно элегантно протестировать. Поскольку сам язык Groovy поддерживаетПрямой доступ к закрытым методам ничем не отличается от доступа к общедоступным методам., поэтому нет необходимости добиваться эффекта единого теста неэлегантными средствами, такими как отражение, изменение прав доступа и размещение тестового класса и тестируемого класса в унифицированном пакете.

Вместо этого вопрос должен быть:«Как и как изящноMockчастный метод? ".

Вот несколько дискуссий о проблеме одиночного теста приватного метода:

Как Spock Mock приватно строит (новый)?

Spock не поддерживает частные, конструктивные и статические методы Mock. Распространенным решением является введение фреймворка, такого как mockito, который поддерживает расширенные насмешки.

Однако совместимость между ними не очень хорошая, каждый раз, когда запускается модульный тест, в консоль будет выводиться следующее приглашение:

Notifications are not supported for behaviour ALL_TESTINSTANCES_ARE_CREATED_FIRST

А после введения еще одного тестового фреймворка читабельность нескольких стилей кода (groovy, Spock, Mockito) в одном тестовом коде сильно снизится.

Поэтому в настоящее время, когда требуются фиктивные частные, статические и новые операции, мы пытаемся избежать этого, изменив код.

Как Spock проверяет выброшенные исключения?

def "test_queryResultAndUpdate"() {
    when: "channelCode is not exist"
    TransRecordPo record1 = new TransRecordPo(extend: "{\"fgMchId\":\"11\"}", state: getRandomValue(TransOrderStatus.NEED_QUERY_STATES))
    BizResult<QueryTransOrderResp> bizResult1 = channelProxyManager.queryResultAndUpdate(record1)

    then:
    FailException e = thrown(FailException.class)
    e.getMessage() == "支付渠道类型映射失败"
}

На официальном сайте Spock говорится, что он поддерживает статические методы Mock, но на самом деле он не работает?

Описание официального сайта:Спок framework.org/Spock/docs/…

Проще говоря, статический метод Спока Mock может воздействовать только на.groovyфайл, да.javaне работает.

Ссылаться на:blog.CSDN.net/Моча Амур/Ах…

Как Спок издевается над частичными моками?

использоватьSpyдля создания объектов, которые требуют только частичного макета. Как показано в следующем примере,ChannelProxyManager#jsApiPayтестируемый метод, в котором метод вызываетсяChannelProxyManager#aliJsApiPayметод. Но сценарии, которые необходимо протестировать в это время, такие же, как иaliJsApiPayНеважно, нужно использоватьSpy

Примечание. Частично имитируемый метод должен быть общедоступным.

def "test_jsApiPay"() {
    ChannelProxyManager spyManager = Spy(ChannelProxyManager,
            constructorArgs: [recordManager, fgMchChannelInfoCacher, serviceConfig, payInfoCacher, weChatPayHelper]) {
    } as ChannelProxyManager
    String payInfo = String.valueOf(System.currentTimeMillis())
    
    when: "ali jsapi order success"
    PayBo payBo2 = new PayBo(fgTransType: FGTransType.ALI_FWC_PAY, payChannelType: PayChannelType.ALI)
    BizResult<String> result2 = spyManager.jsApiPay(payBo2)
    println JacksonUtil.object2Json(result2)
    
    then:
    1 * spyManager.aliJsApiPay(*_) >> BizResult.success(payInfo)
    result2.success
    result2.getData() == payInfo
}

Как распечатать описание блока

stackoverflow.com/questions/4…

Как проверить количество вызовов статического статического метода в сочетании с PowerMock

woohoo.coder.work/article/134…