2009-02-19 11 views
6

Das mag wie eine ziemlich detaillierte Frage über Easymock erscheinen, aber es fällt mir schwer, eine Support-Site/Forum/Mailing-Liste für diese Bibliothek zu finden.Easymock: Ist die Reihenfolge der Eroberungen wichtig?

Ich stoße auf einen Fehler, wenn ich die Methode captures() verwende, die die erfassten Parameter scheinbar außer Betrieb setzt.

Hier ist eine vereinfachte Version von dem, was ich testen:

public class CaptureTest extends TestCase { 

    // interface we will be mocking 
    interface Processor { 
      void process(String x); 
    } 

    // class that uses the interface above which will receive the mock 
    class Component { 

     private Processor processor; 

     private String[] s = { "one", "two", "three", "four" }; 

     Component(Processor processor) { 
      this.processor = processor; 
     } 

     public void doSomething() { 
      for (int i = 0; i < s.length; i++) { 
       processor.process(s[i]); 
      } 
     } 
} 

    public void testCapture() { 

     //create the mock, wire it up  
     Processor mockProcessor = createMock(Processor.class); 
     Component component = new Component(mockProcessor); 

     //we're going to call the process method four times 
     //with different arguments, and we want to capture 
     //the value passed to the mock so we can assert against it later  
     Capture<String> cap1 = new Capture<String>(); 
     Capture<String> cap2 = new Capture<String>(); 
     Capture<String> cap3 = new Capture<String>(); 
     Capture<String> cap4 = new Capture<String>(); 

     mockProcessor.process(and(isA(String.class), capture(cap1))); 
     mockProcessor.process(and(isA(String.class), capture(cap2))); 
     mockProcessor.process(and(isA(String.class), capture(cap3))); 
     mockProcessor.process(and(isA(String.class), capture(cap4))); 

     replay(mockProcessor); 

     component.doSomething(); 

     //check what values were passed to the mock 
     assertEquals("one", cap1.getValue()); 
     assertEquals("two", cap2.getValue()); 
     assertEquals("three", cap3.getValue()); 
     assertEquals("four", cap4.getValue()); 

     verify(mockProcessor); 
    } 

} 

(Bitte beachten Sie, dass dies nur ein vereinfachtes Testfall ist - ich weiß, dass ich den genauen Wert der Argumente angeben konnte ich meinen geben erwarten Spott, aber in meinem realen Fall sind die Argumente komplexe Objekte mit einer Handvoll von Feldern, und ich möchte das Objekt erfassen, so dass ich gegen nur einige dieser Felder behaupten kann, ohne das gesamte Objekt in meinem Testfall neu zu erstellen.

Wenn ich den Test ausführen, scheitert es an:

junit.framework.ComparisonFailure: erwartet: < [one]> aber war: < [vier]>

Was bedeutet, dass die Parameter, den EasyMock in cap1 erfasst, ist nicht der erste Aufruf der Methode, sondern der letzte (da der Wert four ist). Ich bekomme die gleichen Ergebnisse, wenn ich die captures() Deklarationen umkehren, dh cap4 mit dem ersten Methodenaufruf usw.

Dies scheint wie ein Fehler in EasyMock - verschiedene Parameter an die gleiche Methode in verschiedenen Aufrufen don 'don' t scheint korrekt zu erfassen.

Verwendet jemand sonst capture() mit EasyMock und ähnliche Probleme? Gibt es eine einfache Problemumgehung, die Sie kennen, oder eine andere Art, wie ich die Parameter erfassen kann, die an die Methoden meines Mocks übergeben werden?

Update 1: feste Codebeispiel zu zeigen, dass ich createMock verwende, nicht createStrictMock, aber ich habe den gleichen Fehler mit beiden (obwohl der tatsächliche Wert dessen, was Änderungen erfasst wird).

+0

Ich habe dieses Problem untersucht und es ist ziemlich verwirrend. Wenn Sie für jedes Capture eine System.out.println-Anweisung ausführen, sehen Sie Folgendes mit einem createMock: vier, vier, vier, vier. Mit einem createStrickMock: zwei, zwei, drei, vier. – hooknc

+0

Das hört sich definitiv danach an! Ich habe einen Fehler auf Easymocks sourceforge-Seite geschickt, hoffentlich wird jemand antworten - obwohl aus dem Mangel an Mailinglisten, Foren/Kommentaren auf der Homepage, etc. habe ich das Gefühl, dass Unterstützung extrem begrenzt ist :( –

Antwort

4

Ich habe an answer über den Fehler erhalten, den ich an die Easymock sourceforge-Site gesendet habe, und ein Entwickler hat bestätigt, dass es tatsächlich ein Fehler mit dieser Version von Easymock ist.

Es ist in der Tat ein Fehler. Die Erfassung ist abgeschlossen, auch wenn sie bereits durchgeführt wurde. Die aktuelle Problemumgehung ist Ihr eigenes Capture-Objekt zu implementieren und setValue außer Kraft setzen, dies zu tun:

@Override 
public void setValue(T value) { 
    if(!hasCaptured()) { 
    super.setValue(value); 
    } 
} 
-1

Statt EasyMock.createStrictMock aufzurufen (...) rufen Sie einfach EasyMock.createMock (...). Sollte deine Probleme lösen.

+0

Ich hatte die gleichen Probleme with createMock - Ich habe es in createStrickMock geändert (und vergessen, dass es in dem von mir geposteten Codebeispiel war) denke, dass das mit der Reihenfolge der Methodenaufrufe helfen könnte, aber nein - dasselbe Ergebnis. Ich werde das obige Beispiel aktualisieren. –

+0

Hmm, einfach Als Kontrolle könnten Sie versuchen, checkOrder (false) aufzurufen, nachdem Sie den Mock erstellt haben. Ich könnte etwas offensichtliches übersehen haben, aber es sieht wie ein Bug aus. Ich kann es heute Abend auf meinem Rechner bestätigen. –

+0

gleiche Ergebnisse mit checkOrder (falsch) –

0

Sie können auch EasyMock.createNiceMock (...) anstelle von EasyMock.createStrictMock (...) oder EasyMock.createMock (...) verwenden.

Obwohl ich stimme zu, dass es eher wie ein Fehler mit createMock aussieht.

1

Ich spielte mit Ihrem Test herum und konnte nicht lösen. Allerdings habe ich die Capture-Klasse erweitert, um zu sehen, ob die Werte in einer anderen Reihenfolge gesetzt wurden (ich war verdächtig, dass EasyMock intern einen Hash mit einem Schlüssel aus den Methoden und den Parametern verwendete) Auftrag. Aber da ist etwas wirklich Seltsames. Es scheint so, als ob der Algorithmus eine Art zuweisendes Muster hat. Nun lass mich den Code und die seltsame Ausgabe zeigen. Übrigens haben die Änderungen von Mock, NiceMock und StrictMock keinen Unterschied gemacht ..

class MyCapture extends Capture<String> { 

    private String id; 

    public MyCapture(String id) { 
     super(); 
     System.out.printf("Constructor %s expecting %s\n", id, this.getClass().getName()); 
     this.id = id; 
    } 

    private static final long serialVersionUID = 1540983654657997692L; 

    @Override 
    public void setValue(String value) { 
     System.out.printf("setting value %s expecting %s \n", value, id); 
     super.setValue(value); 
    } 

    @Override 
    public String getValue() { 
     System.out 
       .printf("getting value %s expecting %s \n", super.getValue(), id); 
     return super.getValue(); 
    } 
} 


public void testCapture() { 

    // create the mock, wire it up 
    Processor mockProcessor = createStrictMock(Processor.class); 
    Component component = new Component(mockProcessor); 

    // we're going to call the process method four times 
    // with different arguments, and we want to capture 
    // the value passed to the mock so we can assert against it later 
    Capture<String> cap1 = new MyCapture("A"); 
    Capture<String> cap2 = new MyCapture("B"); 
    Capture<String> cap3 = new MyCapture("C"); 
    Capture<String> cap4 = new MyCapture("D"); 

    mockProcessor.process(and(isA(String.class), capture(cap1))); 
    mockProcessor.process(and(isA(String.class), capture(cap2))); 
    mockProcessor.process(and(isA(String.class), capture(cap3))); 
    mockProcessor.process(and(isA(String.class), capture(cap4))); 
    replay(mockProcessor); 

    component.doSomething(); 

    // check what values were passed to the mock 
    assertEquals("A", cap1.getValue()); 
    assertEquals("B", cap2.getValue()); 
    assertEquals("C", cap3.getValue()); 
    assertEquals("D", cap4.getValue()); 

    verify(mockProcessor); 
} 

}

* Und das ist der Ausgang *

Constructor A expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor B expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor C expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    Constructor D expecting com.comp.core.dao.impl.CaptureTest$MyCapture 
    calling process A 
    setting value A expecting A 
    calling process B 
    setting value B expecting A <<Setting the wrong guy 
    setting value B expecting A <<Setting the wrong guy 
    setting value B expecting B <<Ops this is the right one..stop 
    calling process C 
    setting value C expecting B <<Setting the wrong guy 
    setting value C expecting B <<Setting the wrong guy 
    setting value C expecting C <<Setting the wrong guy 
    calling process D 
    setting value D expecting C <<Setting the wrong guy 
    setting value D expecting C <<Setting the wrong guy 
    setting value D expecting D <<Ops this is the right one..stop 
    getting value B expecting A 

Leider habe ich nicht, dass Sie mehr helfen können. Es könnte tatsächlich ein Fehler im einfachen Schein sein.

0

Dies ist ein Problem besser geeignet für zustandsbasierte Tests, glaube ich. Mit JMockit Sie es so lösen könnte:

import mockit.*; 
import static mockit.Mockit.*; 
import mockit.integration.junit3.*; 

public class CaptureTest extends JMockitTestCase 
{ 
    interface Processor { void process(String x); } 

    class Component 
    { 
     private final Processor processor; 
     private final String[] s = {"one", "two", "three", "four"}; 

     Component(Processor processor) { this.processor = processor; } 

     public void doSomething() 
     { 
     for (String value : s) { 
      processor.process(value); 
     } 
     } 
    } 

    @MockClass(realClass = Processor.class) 
    static class MockProcessor 
    { 
     private final String[] expectedValues; 
     private int i; 

     MockProcessor(String... expectedValues) { this.expectedValues = expectedValues; } 

     @Mock 
     void process(String x) 
     { 
     assertEquals(expectedValues[i++], x); 
     } 
    } 

    public void testCapture() 
    { 
     Processor mockProcessor = setUpMock(new MockProcessor("one", "two", "three", "four")); 
     Component component = new Component(mockProcessor); 

     component.doSomething(); 
    } 
} 
0

Kurz gesagt, hier ist was für mich gearbeitet:

MyClass myMock = EasyMock.createStrictMock(MyClass.class); 

...

EasyMock.checkOrder(myMock, true); // before the capture and verify, not sure if it matters 

...

Capture<MyArg> capturedArgs = new Capture<MyArg>(); 
expect(myMock.search(capture(capturedArgs))).andReturn(someRandomReturn); 

PS: Ich benutze E asyMock 3.0