2009-07-23 4 views
34

Ist es möglich, ein Mock-Objekt zu erstellen, das mehrere Schnittstellen mit EasyMock implementiert?Ist es möglich, ein Mock-Objekt zu erstellen, das mehrere Schnittstellen mit EasyMock implementiert?

Zum Beispiel, Schnittstelle Foo und Schnittstelle Closeable?

In Rhino Mocks können Sie beim Erstellen eines Mock-Objekts mehrere Schnittstellen bereitstellen, aber die Methode createMock() von EasyMock verwendet nur einen Typ.

Ist es möglich, dies mit EasyMock zu erreichen, ohne auf den Fallback des Erstellens einer temporären Schnittstelle zurückgreifen zu müssen, die sowohl Foo als auch Closeable erweitert, und sich dann darüber lustig macht?

Antwort

10

EasyMock unterstützt dies nicht, so dass Sie mit Fallback der temporären Schnittstelle stecken bleiben.

Nebenbei rieche ich ein wenig Code Wiff - sollte eine Methode wirklich ein Objekt als 2 verschiedene Dinge behandeln, die Foo und Closeable Schnittstelle in diesem Fall?

Dies bedeutet für mich, dass die Methode mehrere Operationen durchführt und während ich eine dieser Operationen vermuten, ist das Schließen der Closeable, würde es nicht sinnvoller für den aufrufenden Code zu entscheiden, ob die 'schließen ' Wird benötigt?

den Code Strukturierung auf diese Weise die ‚offene‘ und ‚Schließen‘ in der gleichen try ... finally Block hält und IMHO macht den Code lesbarer nicht die Methode allgemeinere zu erwähnen und ermöglicht es Ihnen, Objekte zu übergeben, die nur Foo implementieren.

+4

ich stimme dem zu, aber zu erweitern: wenn du es verwendest Dependency-Injection, und Ihre Klasse benötigt sowohl ein Foo als auch ein Closable, Sie sollten wirklich zwei separate Setter für diese haben. Wenn Sie sich entscheiden, dasselbe Objekt für beide zu injizieren, dann ist das großartig, aber ich denke, dass die getestete Klasse nicht wissen muss, dass sie das gleiche Objekt ist - sie sollte Foo als Foo und Closeable als behandeln eine verschließbare –

+0

Nick, Matt, danke für Ihre Eingabe. Um das Szenario zu verdeutlichen, besteht der Zusammenhang darin, dass Foo eine Schnittstelle für ein modulares Add-In-System ist. Module von Drittanbietern implementieren Foo und werden dann vom Framework instanziiert und verwendet. Sie können optional auch Closeable implementieren. In diesem Fall werden sie vom Framework geschlossen, sobald sie fertig sind. Daher müssen die Komponententests zwei verschiedene Szenarien abdecken: Ein Foo, das auch geschlossen werden kann, und ein Foo, das nicht geschlossen werden kann. Ich hoffe das macht Sinn. –

+1

@NickHolt: Ich würde dir nicht voll und ganz zustimmen. Betrachten Sie den Fall, wenn Sie eine Schnittstelle 'Person' haben, die nur getters (' getFirstName() ',' getAddress() ', ...) und die Schnittstelle' ModifyablePerson' hat, die nur Setter ('setFirstName()', ' setAddress() ', ...). Und jetzt wollen Sie ein SUT testen, das 'Person' übernimmt, aber prüft, ob das Objekt 'instanceof ModifyablePerson' übergeben wurde und etwas darauf basiert. 'Closeable' ist auch ein gutes Beispiel: Wenn das Objekt eine" erweiterte "Funktionalität bietet, die explizit von' instanceof' überprüft und ausgenutzt wird, was ist daran schlecht? –

13

haben Sie so etwas wie in Betracht gezogen:

interface Bar extends Foo, Closeable { 
} 

und dann Mock Schnittstelle Bar?

+1

Ja, ich sah nur, wenn Ich könnte das vermeiden. Per meine Frage: "Ist es möglich, dies mit EasyMock zu erreichen, ohne auf die Möglichkeit zurückzugreifen, ein temporäres Interface zu erstellen, das sowohl Foo als auch Closeable erweitert, und sich dann darüber lustig macht?" –

+0

Ich mag diese Lösung - eine solche Schnittstelle in der Testklasse zu erstellen ist ok für mich, gute Idee ;-) – Betlista

+0

Nicht gerade der Wunsch des OPs aber es funktioniert :) –

2

Nach meinem besten Wissen ist das einzige Mock-Tool für Java, das explizite Unterstützung für das Spotten mehrerer Schnittstellen bietet, JMockit. (Meine Inspiration für das Hinzufügen dieser Funktion kam aus Moq und Rhino Mocks, die .NET-Tools sind.)

Ein Beispiel (aus der mockit.ExpectationsUsingMockedTest JUnit 4 Test-Klasse):


@Test 
public <M extends Dependency & Runnable> void mockParameterWithTwoInterfaces(final M mock) 
{ 
    new Expectations() 
    { 
     { 
     mock.doSomething(true); returns(""); 
     mock.run(); 
     } 
    }; 

    assertEquals("", mock.doSomething(true)); 
    mock.run(); 
} 

Dependency und Runnable Schnittstellen sind. Die doSomething Methode gehört zu der ersten und run zu der zweiten.

+0

Dieses Snippet scheint das Mock-Objekt nicht zu erstellen. Wie würdest du das machen ? –

+0

Der obige Test funktioniert für mich. Hast du es versucht? –

49

Obwohl ich mit Nick Holt Antwort grundsätzlich einverstanden sind, dachte ich, ich möchte darauf hinweisen, dass mockito erlaubt, zu tun, was Sie mit dem folgenden Aufruf fragen:

Foo mock = Mockito.mock(Foo.class, withSettings().extraInterfaces(Bar.class)); 

Offensichtlich haben Sie die Besetzung verwenden müssen: (Bar)mock wenn Sie die Mock als Bar verwenden müssen, aber das Guss werfen wird nicht ClassCastException

Hier ist ein Beispiel, das ein bisschen mehr vollständig ist, wenn auch völlig absurd:

import static org.junit.Assert.fail; 
import org.junit.Test; 
import static org.mockito.Mockito.*; 
import org.mockito.Mockito; 
import static org.hamcrest.MatcherAssert.assertThat; 
import static org.hamcrest.Matchers.*; 
import org.hamcrest.Matchers; 

import java.util.Iterator; 


public class NonsensicalTest { 


    @Test 
    public void testRunnableIterator() { 
     // This test passes. 

     final Runnable runnable = 
        mock(Runnable.class, withSettings().extraInterfaces(Iterator.class)); 
     final Iterator iterator = (Iterator) runnable; 
     when(iterator.next()).thenReturn("a", 2); 
     doThrow(new IllegalStateException()).when(runnable).run(); 

     assertThat(iterator.next(), is(Matchers.<Object>equalTo("a"))); 

     try { 
      runnable.run(); 
      fail(); 
     } 
     catch (IllegalStateException e) { 
     } 
    } 
2

Eine weitere Möglichkeit, dieses Problem zu lösen, ist ein verwenden CGLib mixin:

final Interface1 interface1 = mockery.mock(Interface1.class); 
final Interface2 interface2 = mockery.mock(Interface2.class); 

service.setDependence(Mixin.create(new Object[]{ interface1, interface2 })); 

mockery.checking(new Expectations(){{ 
    oneOf(interface1).doSomething(); 
    oneOf(interface2).doNothing(); 
}}); 

service.execute(); 

Unabhängig davon, ob dies eine gute Idee ist, ist es etwas, bis zu Diskussion ...

Verwandte Themen