Prüfling: Impl oder Interface?

Angenommen, ich habe eine Schnittstelle und eine Implementierungsklasse, die diese implementiert, und ich möchte einen Unit-Test dafür schreiben. Was soll ich Interface oder Impl testen?

Hier ist ein Beispiel:

public interface HelloInterface {
    public void sayHello();
}


public class HelloInterfaceImpl implements HelloInterface {
    private PrintStream target = System.out;


    @Override
    public void sayHello() {
        target.print("Hello World");

    }

    public void setTarget(PrintStream target){
        this.target = target;
    }
}

Also habe ich HelloInterface und HelloInterfaceImpl, die es implementieren. Was ist die zu testende Schnittstelle oder Impl?

Ich denke, es sollte HelloInterface sein. Betrachten Sie die folgende Skizze des JUnit-Tests:

public class HelloInterfaceTest {
    private HelloInterface hi;

    @Before
    public void setUp() {
        hi = new HelloInterfaceImpl();
    }

    @Test
    public void testDefaultBehaviourEndsNormally() {
        hi.sayHello();
        // no NullPointerException here
    }

    @Test
    public void testCheckHelloWorld() throws Exception {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream target = new PrintStream(out);
        PrivilegedAccessor.setValue(hi, "target", target);
        //You can use ReflectionTestUtils in place of PrivilegedAccessor
        //really it is DI 
        //((HelloInterfaceImpl)hi).setTarget(target);
        hi.sayHello();
        String result = out.toString();
        assertEquals("Hello World", result);

    }
 }

Die Hauptzeile ist eigentlich eine, die ich auskommentiert habe.

((HelloInterfaceImpl)hi).setTarget(target);

MethodesetTarget() ist nicht Teil meiner öffentlichen Benutzeroberfläche, daher möchte ich nichtzufällig nennen. Wenn ich es wirklich anrufen möchte, sollte ich mir einen Moment Zeit nehmen und darüber nachdenken. Es hilft mir zum Beispiel herauszufinden, dass ich wirklich Abhängigkeitsinjektion versuche. Es eröffnet mir die ganze Welt der neuen Möglichkeiten. Ich kann einen vorhandenen Abhängigkeitsinjektionsmechanismus (z. B. Spring) verwenden und ihn selbst simulieren, wie ich es tatsächlich in meinem Code getan habe, oder einen völlig anderen Ansatz verfolgen. Schauen Sie genauer hin, die Vorbereitung von PrintSream war nicht so einfach, vielleicht sollte ich stattdessen ein Scheinobjekt verwenden?

BEARBEITEN: Ich denke Ich sollteimmer konzentrieren sie sich auf die schnittstelle. Aus meiner SichtsetTarget() ist nicht Teil des "Vertrags" der impl-Klasse und dient auch nicht zur Abhängigkeitsinjektion. Ich denke, jede öffentliche Methode der Impl-Klasse sollte aus der Testperspektive als privat betrachtet werden. Dies bedeutet jedoch nicht, dass ich die Implementierungsdetails ignoriere.

Siehe auchSollten sich Private / Protected-Methoden im Unit-Test befinden?

EDIT-2 Bei mehreren Implementierungen / mehreren Schnittstellen würde ich alle Implementierungen testen, aber wenn ich eine Variable in my deklarieresetUp() Methode würde ich auf jeden Fall Schnittstelle verwenden.

Antworten auf die Frage(4)

Ihre Antwort auf die Frage