2014-12-12 4 views
11

Wie stelle ich mir processMessage() mit Spock vor, so dass ich überprüfen kann, dass processBulkMessage() processMessage() n mal aufruft, wobei n die Anzahl der Nachrichten in einer BulkMessage ist?Grails/Spock: Wie man einzelne Methode innerhalb der Klasse vortäuscht, in der Methode innerhalb der Klasse selbst aufgerufen wird?

class BulkMessage { 
    List messages 
} 

class MyService { 

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

    def processMessage(Message message) { 

    } 
} 

Antwort

5

Sie können spies und teilweise verwenden Mocks (benötigt Spock 0.7 oder neuer).

Nach einem Spion Erstellen Sie auf das Gespräch zwischen dem Anrufer mithören kann und dem realen Gegenstand der unter dem Spion:

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

Manchmal ist es wünschenswert, sowohl einige Code ausführen und delegieren an die Real Methode:

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

Es verwendet nicht Spock integrierte API Mocking (nicht sicher, wie teilweise ein Objekt zu verspotten), aber dies den Trick tun soll:

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 Meiner Meinung nach ist das keine gut durchdachte Lösung. Tests und Design gehen Hand in Hand - ich empfehle this sprechen, um es besser zu untersuchen. Wenn geprüft werden muss, ob eine andere Methode für ein zu testendes Objekt aufgerufen wurde, sollte es in ein anderes Objekt mit anderer Zuständigkeit verschoben werden.

So würde ich es machen. Ich weiß, wie die Sichtbarkeit groovy funktioniert, also denke an die Kommentare.

@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

Vielen Dank - ich habe das gerade überarbeitet und haben viel über Design gelernt, da ich die Frage gestellt. Ich stimme Ihnen jetzt zu, dass das bessere Design ein bulkMessageProcessingService und ein individualMessageProcessingService wären. Testen ist daher trivial mit einem Schein. – John

1

Für Java Frühling Leute Tests in Spock:

constructorArgs ist der Weg zu gehen, aber Konstruktor Injektion verwenden. Mit Spy() können Sie nicht automatisch markierte Felder direkt einstellen.

// **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" 
    } 
}  

Spock - Anstoßen void-Methode auf Spy Objekt

// **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: 
      ... 
    } 
}