2016-04-03 7 views
4

Meine Frage bezieht sich auf das Testen einer Klasse, die viele Schnittstellen implementiert. Zum Beispiel habe ich diese Klasse:Wie können wir testen, dass eine Klasse viele Schnittstellen implementiert?

public class ServiceControllerImpl extends ServiceController implements IDataChanged, IEventChanged { 

} 

Jetzt gibt es zwei Möglichkeiten zum Testen. Die erste testet direkt auf der konkreten Klasse. Das bedeutet, der Objekttyp ist die konkrete Klasse und nicht die Schnittstelle.

public class ServiceControllerImplTest { 
    ServiceControllerImpl instance; 
    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     // you can bring this instance anywhere 
    } 
} 

Die zweite Möglichkeit besteht darin, nur die Schnittstelle zu testen. Wir müssen dieses Objekt auf alle Schnittstellen schreiben, die es implementiert.

public class ServiceControllerImplTest { 
    ServiceController instance;  // use interface here 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     dataChangeListener = (IDataChanged) instance; 
     // instance and dataChangeListener "look like" two different object. 
    } 
} 

Ich ziehe die zweite Lösung, weil vielleicht in Zukunft werden wir die Schnittstelle an andere Objekte implementiert ändern können, so die konkrete Klasse unter Verwendung könnte in Zukunft vorgeschriebenen Prüfungen nicht führen. Ich kenne die Best Practice für dieses Problem nicht.

Thanks :)

+2

Yeah zum Testen einer Schnittstelle, die Sie auf dem Schnittstellentyp testen. Also ist Ihre zweite Lösung im Grunde genommen der Weg zu gehen. – JayC667

+1

Ich bin sicher, der obige Kommentar gibt die Antwort, aber Ihre Frage braucht ein wenig Klärung. Wenn Sie 'dataChangeListener = (IDataChanged) dataChangeListener;' geschrieben haben, meinten Sie 'dataChangeListener = (IDataChanged) instance;', oder? –

+0

@DaveSchweisguth ja. Ich habe bearbeitet. vielen Dank. – hqt

Antwort

1

Ich ziehe zweite Lösung, da in Wirklichkeit vielleicht in Zukunft können wir die Schnittstelle ändern Sie es auf andere Objekte implementiert, so zwingen, mit betonierte Klasse führt möglicherweise zu einem Fehlschlagstest in der Zukunft.

Ich denke, es wird sowieso zu fehlgeschlagenen Tests führen, weil Sie normalerweise testen, ob die Aussagen wahr oder falsch sind. Die Frage ist: Trifft dieser Test für alle IDataChanged oder gelten diese Aussagen nur für die ServiceControllerImpl?

Wenn die Behauptungen nur auf die ServiceControllerImpl anwenden es keine Rolle spielt, wenn Sie einen IDataChanged anstelle eines ServiceControllerImpl verwenden, da Sie den Test bearbeiten müssen, wenn Sie ein anderes verwenden IDataChanged Objekt - unterschiedliche Aussagen. Der Test schlägt fehl, wenn Sie ein anderes Objekt verwenden.

Die Art, wie Sie Unit-Tests einrichten, gibt Ihnen eine Antwort. Ein Komponententest testet normalerweise eine Klasse isoliert. Dies bedeutet, dass Sie die Umgebung verspotten. Wenn Sie sich jedoch über die Umgebung lustig machen, kennen Sie die Abhängigkeiten der Klasse, die Sie testen, und dies sind Implementierungsdetails. Ihr Test wird also auf einer Implementierungsbasis und nicht nur auf der Oberfläche geschrieben.

Es ist möglich, Tests zu schreiben, die nur eine abstrakte API testen - wie eine Schnittstelle. Aber das bedeutet normalerweise, dass Ihre Tests auch abstrakt sind. Z.B.

Sie können diese abstrakten Tests dann erweitern, um die API für konkrete Klassen zu testen. Z.B.

In diesem Fall können Sie die Implementierung ersetzen und der Test muss grün bleiben.

Aber hier ist ein weiteres Beispiel für eine abstrakte API, wenn das Ersetzen des zu testenden Objekts nicht wirklich sinnvoll ist. Was ist mit dem Schreiben eines Tests für alle Runnable s?

public class RunnableTest { 

    @Test 
    public void run(){ 
     Runnable runnable = ...; 

     // What to test here? 
     // run is invoked without throwing any runtime exceptions? 
     runnable.run(); 

    } 
} 

Wie man sieht es nicht sinnvoll in einigen Fällen macht Tests in einer Art und Weise zu schreiben, so dass Sie leicht das Objekt unter Test ersetzen können.

Wenn eine API wie die Set API eine konkrete Statusbehandlung definiert, können Sie abstrakte Tests schreiben, die dies testen.

1

JayC667 bereits richtig beantwortet, dass sie von diesen Typen definierten eine Klasse durch seinen übergeordneten Typen (en) in den Tests von Methoden beziehen am besten sind. Aber ich würde die Art und Weise haben Sie das ein bisschen Casting zu vermeiden:

public class ServiceControllerImplTest { 
    ServiceController controller; 
    IDataChanged dataChangeListener; 

    @Before 
    public void setUp() { 
     instance = new ServiceControllerImpl(); 
     controller = instance; 
     dataChangeListener = instance; 
    } 
} 
Verwandte Themen