java - showconfirmdialog - joptionpane showoptiondialog



Mockito wenn/dann nicht den erwarteten Wert zurückgeben (1)

Ich versuche, diese getKeyFromStream-Methode mit den "Any" -Matchern auszugeben. Ich habe versucht, expliziter und weniger explizit (anyObject ()), aber es scheint, dass egal, was ich versuche, dieser Stub nicht den fooKey in meinem Komponententest zurückgeben wird.

Ich frage mich, ob es daran liegt, dass es geschützt ist oder dass etwas anderes fehlt oder falsch funktioniert. Ich habe andere wenn / dann Aussagen während der Tests, die funktionieren, aber aus irgendeinem Grund hier ist es nicht.

Hinweis: Der getKeyFromStream verwendet im Allgemeinen einen byteArrayInputStream, aber ich versuche, es mit einem InputStream zu vergleichen, habe ich beide vergeblich versucht.

public class FooKeyRetriever() //Mocked this guy
{
    public FooKey getKey(String keyName) throws KeyException {

        return getKeyFromStream(getKeyStream(keyName, false), keyName);
    }

    //Stubbed this method to return a key object which has been mocked
    protected FooKey getKeyFromStream(InputStream keyStream, String keyName){
        //Some code
        return fooKey;
    }
}

Gerätetest

@Mock
private FooKeyRetriever mockKeyRetriever;

@Mock
private FooKey fooKey;

@Before
public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
}

@Test
public void testGetFooKey() throws Exception {



    when(foo.getKeyFromStream(any(InputStream.class),any(String.class))).thenReturn(fooKey);

    FooKey fooKey = mockKeyRetriever.getKey("irrelevant_key");

    assertNotNull(fooKey);
}

Das Problem mit dem Komponententest besteht darin, dass Sie versuchen, eine Methode Ihrer tatsächlichen Klasse zu verspotten, die Sie testen möchten, aber Sie können tatsächlich keine Pseudo-Methode aufrufen, da dies null zurückgibt, sofern Sie keinen verspotteten Rückgabewert angeben aufgerufene Methode. Normalerweise mockst du nur externe Abhängigkeiten.

Es gibt zwei Möglichkeiten, Testobjekte zu erstellen: mock und spy . Der Primer 1 erstellt ein neues Objekt basierend auf der von Ihnen angegebenen Klasse, die den internen Status null hat und auch bei jeder aufgerufenen Methode null zurückgibt. Aus diesem Grund müssen Sie bestimmte Rückgabewerte für Methodenaufrufe definieren. spy hingegen erzeugt ein reales Objekt und fängt Methodenaufrufe ab, wenn für bestimmte Methoden "Scheindefinitionen" definiert sind.

Mockito und PowerMock bieten zwei Möglichkeiten, Ihre verspotteten Methoden zu definieren:

// method 1
when(mockedObject.methodToMock(any(Param1.class), any(Param2.class),...)
    .thenReturn(answer);
when(mockedObject, method(Dependency.class, "methodToMock", Parameter1.class, Parameter2.class, ...)
    .thenReturn(answer);

oder

// method 2
doReturn(answer).when(mockedObject).methodToMock(param1, param2);

Der Unterschied ist, dass die method 1 die Methodenimplementierung ausführt, während die spätere nicht. Dies ist wichtig, wenn Sie mit spy Objekten arbeiten, da Sie manchmal nicht den echten Code in der aufgerufenen Methode ausführen wollen, sondern nur den Code ersetzen oder einen vordefinierten Wert zurückgeben!

Obwohl Mockito und PowerMock eine doCallRealMethod() die Sie anstelle von doReturn(...) oder doThrow(...) , wird dies den Code innerhalb Ihres realen Objekts aufrufen und ausführen und alle Rückgabeanweisungen von doReturn(...) Methoden ignorieren. Dies ist jedoch in Ihrem Fall, in dem Sie eine Methode Ihrer zu testenden Klasse ausprobieren möchten, nicht hilfreich.

Eine Methodenimplementierung kann durch "überschrieben" werden

doAnswer(Answer<T>() { 
    @Override 
    public T answer(InvocationOnMock invocation) throws Throwable {
        ...
    }
)

wo Sie einfach erklären können, was die Logik der aufgerufenen Methode sein soll. Sie können dies verwenden, um das Scheinergebnis der geschützten Methode folgendermaßen zurückzugeben:

import static org.hamcrest.core.IsSame.sameInstance;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;

import java.io.InputStream;

import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

public class FooKeyRetrieverTest {

    @Test
    public void testGetFooKey() throws Exception {
        // Arrange
        final FooKeyRetriever sut = spy(new FooKeyRetriever());
        FooKey mockedKey = mock(FooKey.class);

        doReturn(mockedKey)
            .when(sut).getKeyFromStream(any(InputStream.class), anyString());
        doAnswer(new Answer<FooKey>() {

            public FooKey answer(InvocationOnMock invocation) throws Throwable {
                return sut.getKeyFromStream(null, "");
            }
        }).when(sut).getKey(anyString());

        // Act
        FooKey ret = sut.getKey("test");

        // Assert
        assertThat(ret, sameInstance(mockedKey));
    }
}

Der obige Code funktioniert, beachten Sie jedoch, dass dies dieselbe Semantik hat, wie einfach einen Rückgabewert für den getKey(...) as zu deklarieren

doReturn(mockedKey).when(sut).getKey(anyString());

Versuchen Sie, nur getKeyFromStream(...) mit etwas wie diesem zu ändern:

doReturn(mockedKey)
    .when(sut).getKeyFromStream(any(InputStream.class), anyString());

Ohne Änderung von getKey(...) Ihres System-Under-Test (SUT) wird nichts erreicht, da der echte Code von getKey(...) ausgeführt würde. Wenn Sie jedoch das sut-Objekt vortäuschen, können Sie die Methode in Ihrem // Act Abschnitt nicht aufrufen, da dies null zurückgeben würde. Wenn du es versuchst

doCallRealMethod().when(sut).getKey(anyString());

Auf einem Mock-Objekt würde die echte Methode aufgerufen werden, und wie zuvor erwähnt, würde dies auch die realen Implementierungen von getKeyFromStream(...) und getKeyStream(...) unabhängig davon, was Sie als Mock-Methode angegeben haben.

Wie Sie wahrscheinlich selbst sehen können, ist das Spotten von Methoden Ihrer tatsächlichen Klasse nicht so nützlich und belastet Sie mehr, als es Ihnen gut tut. Daher liegt es an Ihnen oder der Unternehmensrichtlinie, ob Sie private / geschützte Methoden überhaupt testen möchten oder müssen oder ob Sie nur die öffentliche API testen (was ich empfehlen würde). Sie haben auch die Möglichkeit, Ihren Code zu refaktorieren , um die Testbarkeit zu verbessern, obwohl die primäre Absicht des Refactorings sein sollte, das Gesamtdesign Ihres Codes zu verbessern .





stubbing