2014-12-12 2 views
11

Учитывая следующее, как я могу mock processMessage() использовать Spock, чтобы я мог проверить, что processBulkMessage() вызывает processMessage() n раз, где n - количество сообщений в BulkMessage?Grails/Spock: Как издеваться над одним методом внутри класса, где метод вызывается из самого класса?

class BulkMessage { 
    List messages 
} 

class MyService { 

    def processBulkMessage(BulkMessage msg) { 
     msg.messages.each {subMsg-> 
      processMessage(subMsg) 
     } 
    } 

    def processMessage(Message message) { 

    } 
} 

ответ

5

Вы можете использовать spies и частичный издевается (требуется Spock 0.7 или новее).

После создания шпиона, вы можете слушать в разговоре между абонентом и реальным объектом, лежащим в основе шпиона:

def subscriber = Spy(SubscriberImpl, constructorArgs: ["Fred"]) 
subscriber.receive(_) >> "ok" 

Иногда желательно как выполнить некоторый код и делегировать реальный способ:

subscriber.receive(_) >> { String message -> callRealMethod(); message.size() > 3 ? "ok" : "fail" } 
1

Он не использует Спки встроенных Дразнящего API (не уверен, как частично издеваться объект), но это следует сделать трюк:

class FooSpec extends Specification { 

    void "Test message processing"() { 
     given: "A Bulk Message" 
     BulkMessage bulk = new BulkMessage(messages: ['a', 'b', 'c']) 

     when: "Service is called" 
     def processMessageCount = 0 
     MyService.metaClass.processMessage { message -> processMessageCount++ } 
     def service = new MyService() 
     service.processBulkMessage(bulk) 

     then: "Each message is processed separately" 
     processMessageCount == bulk.messages.size() 
    } 
} 
2

I По моему мнению, это не хорошо разработанное решение. Тесты и дизайн идут рука об руку - рекомендую this поговорить, чтобы исследовать его лучше. Если есть необходимость проверить, был ли вызван другой метод на проверяемом объекте, кажется, что он должен быть перенесен на другой объект с другой ответственностью.

Вот как я это сделаю. Я знаю, как видимость работает в groovy, так что заметьте комментарии.

@Grab('org.spockframework:spock-core:0.7-groovy-2.0') 
@Grab('cglib:cglib-nodep:3.1') 

import spock.lang.* 

class MessageServiceSpec extends Specification { 

    def 'test'() { 
     given: 
     def service = new MessageService() 
     def sender = GroovyMock(MessageSender) 

     and: 
     service.sender = sender 

     when: 
     service.sendMessages(['1','2','3']) 

     then: 
     3 * sender.sendMessage(_) 
    } 
} 
class MessageSender { //package access - low level 
    def sendMessage(String message) { 
     //whatever 
    } 
} 

class MessageService { 

    MessageSender sender //package access - low level 

    def sendMessages(Iterable<String> messages) { 
     messages.each { m -> sender.sendMessage(m) } 
    } 
} 
+0

Спасибо - я только что вновь это и узнали много нового о дизайне, так как я задал вопрос. Теперь я согласен с вами в том, что лучшим дизайном будет функция bulkMessageProcessingService и individualMessageProcessingService. Таким образом, тестирование является тривиальным с макетом. – John

1

Для Java Spring тестирования людей в Спока:

constructorArgs это путь, но использовать инъекции конструктор. Spy() не позволит вам автоматически устанавливать поля автоматически.

// **Java Spring** 
class A { 
    private ARepository aRepository; 

    @Autowire 
    public A(aRepository aRepository){ 
     this.aRepository = aRepository; 
    } 

    public String getOne(String id) { 
     tryStubMe(id) // STUBBED. WILL RETURN "XXX" 
     ... 
    } 

    public String tryStubMe(String id) { 
     return aRepository.findOne(id) 
    } 

    public void tryStubVoid(String id) { 
     aRepository.findOne(id) 
    } 
} 

// **Groovy Spock** 
class ATest extends Specification { 

    def 'lets stub that sucker' { 
     setup: 
      ARepository aRepository = Mock() 
      A a = Spy(A, constructorArgs: [aRepository]) 
     when: 
      a.getOne() 
     then: 
      // Stub tryStubMe() on a spy 
      // Make it return "XXX" 
      // Verify it was called once 
      1 * a.tryStubMe("1") >> "XXX" 
    } 
}  

Спок - гася недействительным метод на Spy очень приемлю

// **Groovy Spock** 
class ATest extends Specification { 

    def 'lets stub that sucker' { 
     setup: 
      ARepository aRepository = Mock() 
      A a = Spy(A, constructorArgs: [aRepository]) { 
       1 * tryStubVoid(_) >> {} 
      } 
     when: 
      ... 
     then: 
      ... 
    } 
} 
Смежные вопросы