Jednostka testowana: Impl lub Interface?

Przypuśćmy, że mam interfejs i klasę implementacji, która go implementuje i chcę dla tego napisać test jednostkowy. Co powinienem testować interfejs lub Impl?

Oto przykład:

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;
    }
}

Mam więc HelloInterface i HelloInterfaceImpl, które go implementują. Co to jest interfejs jednostki pod testem lub Impl?

Myślę, że powinien to być HelloInterface. Rozważ następujący szkic testu JUnit:

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);

    }
 }

Główna linia jest właściwie tą, którą skomentowałem.

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

metodasetTarget() nie jest częścią mojego publicznego interfejsu, więc nie chcęprzypadkowo nazwać. Jeśli naprawdę chcę to nazwać, powinienem poświęcić chwilę i pomyśleć o tym. Pomaga mi, na przykład, odkryć, że to, co naprawdę próbuję zrobić, to wstrzyknięcie zależności. Otwiera mi cały świat nowych możliwości. Mogę użyć jakiegoś istniejącego mechanizmu wstrzykiwania zależności (na przykład Springa), mogę sam go zasymulować, tak jak to zrobiłem w moim kodzie, albo przyjąć zupełnie inne podejście. Przyjrzyj się bliżej, przygotowanie PrintSream nie było takie proste, może zamiast tego powinienem użyć makiety?

EDYTOWAĆ: Myślę, że powinienemzawsze skup się na interfejsie. Z mojego punktu widzeniasetTarget() nie jest też częścią „kontraktu” klasy impl, służy sally do wstrzykiwania zależności. Myślę, że każda publiczna metoda klasy Impl powinna być traktowana jako prywatna z perspektywy testowania. Nie oznacza to jednak, że ignoruję szczegóły implementacji.

Zobacz teżCzy metody prywatne / chronione powinny podlegać testowi jednostkowemu?

EDIT-2 W przypadku wielu implementacji wiele interfejsów testowałbym wszystkie implementacje, ale kiedy deklaruję zmienną w moimsetUp() metoda, którą zdecydowanie używałbym interfejsu.

questionAnswers(4)

yourAnswerToTheQuestion