Как я могу проверить, что поле имеет определенное значение? - PullRequest
0 голосов
/ 07 мая 2018

Это кажется основным, поэтому я ожидаю, что это будет обманом ... но я не нашел ничего, что ответило бы на этот вопрос.

Мой код приложения также Groovy. Скажи, у меня есть поле

def something

и в моем тесте (где CUT - это Спок Spy) я запускаю метод, в середине которого есть строка

something = null 

или

something = new Bubble()

... Я просто пытаюсь найти способ проверить, что что-то действительно было установлено на null (или любое значение ...)

В моем then блоке я пробовал:

1 * spyCUT.setSomething( null ) 

и

1 * spyCUT.setSomething(_)

и

1 * spyCUT.set( 'something', _ )

Кстати, в ответ на возражение, что я могу просто проверить значение something в блоке then, ситуация такова, что something должен быть установлен сначала на одно значение, а затем на другое в Конечно, этот метод ...

Прочитав Groovy в действии, 2-е издание У меня самые смутные представления о том, как Groovy работает с получением и настройкой полей ... Понятно, недостаточно.

MCVE (FWIW!)

class Spocko {
    def something

    def doStuff() {
        something = 'fruit'
    }
}

class SpockoTest extends Specification {
    def 'test it'(){
        given:
        Spocko spySpocko = Spy( Spocko )

        when:
        spySpocko.doStuff()

        then:
        1 * spySpocko.setSomething(_)
    }
}

ПОЗЖЕ (после очень полезного ответа kriegaex)

С указанным выше SpockTest, где setSomething равно , вызванному:

class Spocko {
    def something

    def doStuff() {
        this.each{
            it.something = 'fruit' 
        }
    }
}

... проходит! Я пытаюсь понять, почему ...

Кстати, я также обнаружил, что следующие проходы (и не без закрытия):

1 * spySpocko.setProperty( 'something', _ )

1 Ответ

0 голосов
/ 09 мая 2018

После того как я увидел ваш MCVE, на вопрос можно ответить следующим образом: вы не можете проверить вызов метода, который никогда не происходит. doStuff() просто присваивает значение полю, оно не вызывает метод установки внутри. Посмотрите на это:

package de.scrum_master.stackoverflow

import spock.lang.Specification

class SpockoTest extends Specification {
  static class Spocko {
    def something

    def doStuff() {
      something = 'fruit'
    }

    def doMoreStuff() {
      setSomething('vegetable')
    }
  }

  def 'test it'(){
    given: 'Spocko spy'
    Spocko spySpocko = Spy(Spocko)

    when: 'calling method assigning value to property'
    spySpocko.doStuff()

    then: 'no setter is called'
    0 * spySpocko.setSomething(_)
    spySpocko.something == 'fruit'

    when: 'calling method using setter'
    spySpocko.doMoreStuff()

    then: 'setter gets called'
    1 * spySpocko.setSomething('vegetable')

    when: 'using Groovy setter-like syntax from another class'
    spySpocko.something = 'fish'

    then: 'actually a setter gets called'
    1 * spySpocko.setSomething('fish')
  }
}

Вот что происходит. При звонке

javap -v target/test-classes/de/scrum_master/stackoverflow/SpockoTest\$Spocko.class

Вы видите (вывод сокращен):

public java.lang.Object doStuff();
  descriptor: ()Ljava/lang/Object;
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=3, args_size=1
       0: invokestatic  #24                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
       3: astore_1
       4: ldc           #36                 // String fruit
       6: astore_2
       7: aload_2
       8: aload_0
       9: swap
      10: putfield      #38                 // Field something:Ljava/lang/Object;
      13: aload_2
      14: areturn
      15: aconst_null
      16: areturn

public java.lang.Object doMoreStuff();
  descriptor: ()Ljava/lang/Object;
  flags: ACC_PUBLIC
  Code:
    stack=3, locals=2, args_size=1
       0: invokestatic  #24                 // Method $getCallSiteArray:()[Lorg/codehaus/groovy/runtime/callsite/CallSite;
       3: astore_1
       4: aload_1
       5: ldc           #40                 // int 0
       7: aaload
       8: aload_0
       9: ldc           #42                 // String vegetable
      11: invokeinterface #48,  3           // InterfaceMethod org/codehaus/groovy/runtime/callsite/CallSite.callCurrent:(Lgroovy/lang/GroovyObject;Ljava/lang/Object;)Ljava/lang/Object;
      16: areturn
      17: aconst_null
      18: areturn

Можете ли вы заметить разницу?


Обновление после редактирования вопроса 2: Вы хотели знать, почему это вызывает вызов сеттера:

def doStuff() {
  this.each {
    it.something = 'fruit' 
  }
}

Это потому, что this предоставляется замыканию в качестве параметра, поэтому it.something = 'fruit' разрешается динамически, как в моем примере spySpocko.something = 'fish', потому что это не внутреннее присваивание, как в something = 'fruit' (эквивалентно * 1023). *) больше.

На самом деле я думаю, что это не так сложно понять, даже не глядя на байт-код, а просто следуя обычным учебным пособиям по Groovy. Я повторяюсь, но я думаю, что вы слишком сильно усложняете и слишком усложняете, слишком глубоко тестируете. Я бы не ставил подобные тесты в базу производственного кода. Попробуйте проверить поведение ваших классов (подумайте о спецификациях и возможностях!), А не о хитросплетениях внутренностей. Но если это поможет вам понять, как работает Groovy, просто продолжайте играть.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...