Suche…


Bemerkungen

Mockito ist ein Java-Mocking-Framework, das die Möglichkeit bietet, rein lesbare Komponententests mithilfe seiner einfachen API zu schreiben. Es unterscheidet sich von anderen Mocking-Frameworks dadurch, dass das von den meisten anderen Frameworks verwendete Expect-Run-Verify-Muster beibehalten wird.

Stattdessen kennt es nur einen Weg, um (nicht endgültige) Klassen und Schnittstellen zu verspotten, und ermöglicht das Überprüfen und Stubing auf der Grundlage flexibler Argumentvergleicher.

Die aktuelle Version 1.10.19 wird am besten mit maven erstellt

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.19</version>
</dependency>

oder gradle

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }

Version 2 ist noch in der Beta.

Versionen

Ausführung Maven Central Versionshinweise Veröffentlichungsdatum
2.1.0 Mockito-Kern Änderungen 2016-10-04
1.10.19 Mockito-Kern Änderungen 2014-12-31

Einfacher Unit-Test mit Mockito

Die Klasse, die wir testen werden, lautet:

public class Service {

    private Collaborator collaborator;

    public Service(Collaborator collaborator) {
        this.collaborator = collaborator;
    }
    
    public String performService(String input) {
        return collaborator.transformString(input);
    }
}

Sein Mitarbeiter ist:

public class Collaborator {

    public String transformString(String input) {
        return doStuff();
    }

    private String doStuff() {
        // This method may be full of bugs
        . . .
        return someString;
    }

}

In unserem Test wollen wir die Abhängigkeit von Collaborator und seinen Fehlern brechen, also werden wir Collaborator verspotten:

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import org.junit.Test;

public class ServiceTest {
    @Test
    public void testPerformService() throws Exception {
        // Configure mock
        Collaborator collaboratorMock = mock(Collaborator.class);
        doReturn("output").when(collaboratorMock).transformString("input");

        // Perform the test
        Service service = new Service(collaboratorMock);
        String actual = service.performService("input");
        
        // Junit asserts
        String expected = "output";
        assertEquals(expected, actual);
    }  
}

Verwenden von Mockito-Anmerkungen

Die Klasse, die wir testen werden, lautet:

public class Service{

    private Collaborator collaborator;

    public Service(Collaborator collaborator){
        this.collaborator = collaborator;
    }
    
    
    public String performService(String input){
        return collaborator.transformString(input);
    }
}

Sein Mitarbeiter ist:

public class Collaborator {

    public String transformString(String input){
        return doStuff();
    }

    private String doStuff()
    {
        // This method may be full of bugs
        . . .
        return someString;
    }

}

In unserem Test wollen wir die Abhängigkeit von Collaborator und seinen Fehlern brechen, also werden wir Collaborator verspotten. Mit der @Mock Annotation können Sie für jeden Test verschiedene Instanzen von Mocks erstellen:

import static org.junit.Assert.*;
import static org.mockito.Mockito.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.InjectMocks;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class ServiceTest {

    @Mock
    private Collaborator collaboratorMock;

    @InjectMocks
    private Service service;
    
    @Test
    public void testPerformService() throws Exception {
        // Configure mock
        doReturn("output").when(collaboratorMock).transformString("input");            

        // Perform the test
        String actual = service.performService("input");
        
        // Junit asserts
        String expected = "output";
        assertEquals(expected, actual);
    }
    
    
    @Test(expected=Exception.class)
    public void testPerformServiceShouldFail() throws Exception {
        // Configure mock
        doThrow(new Exception()).when(collaboratorMock).transformString("input");

        // Perform the test
        service.performService("input");
    }
}

Mockito versucht, die Abhängigkeitsinjektion in der folgenden Reihenfolge aufzulösen:

  1. Konstruktor-basierte Injection- Mocks werden mit den meisten Argumenten in den Konstruktor eingefügt (wenn einige Argumente nicht gefunden werden können, werden Nullen übergeben). Wenn ein Objekt erfolgreich über den Konstruktor erstellt wurde, werden keine anderen Strategien angewendet.
  2. Setter-basierte Injektion - Mocks werden nach Typ eingespritzt. Wenn mehrere Eigenschaften desselben Typs vorhanden sind, werden die Eigenschaftsnamen und die Modellnamen abgeglichen.
  3. Direkte Feldinjektion - wie bei der Setter-basierten Injektion.

Beachten Sie, dass kein Fehler gemeldet wird, falls eine der zuvor genannten Strategien fehlschlug.

Ausführliche Informationen zu diesem Mechanismus finden Sie in der neuesten Version von Mockito unter den neuesten @InjectMocks .

Installation und Einrichtung

Installation

Die bevorzugte Installationsmethode für Mockito besteht darin, eine Abhängigkeit vom mockito-core mit einem Build-System der Wahl mockito-core . Seit dem 22. Juli 2016 ist die neueste Nicht-Beta-Version 1.10.19. Die Migration zu 2.x ist jedoch bereits empfohlen.

Maven

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>

Gradle

repositories { jcenter() }
dependencies { testCompile "org.mockito:mockito-core:1.+" }

Es gibt auch mockito-all das neben Mockito selbst Hamcrest und Objenesis enthält. Es wird über Maven hauptsächlich für Ameisenbenutzer ausgeliefert, der Vertrieb wurde jedoch in Mockito 2.x eingestellt.


Einführen

Die meisten Einrichtungen von Mockito sind statische Methoden von org.mockito.Mockito . So kann Mockito auf diese Weise statisch in eine Klasse importiert werden:

import static org.mockito.Mockito.*;

Der Dokumentations-Einstiegspunkt befindet sich im Javadoc dieser Klasse.

Verspotten Sie einige Methoden für ein Objekt

Einige Methoden eines Objekts können mit spy() von Mockito verspottet werden.

Stellen Sie sich zum Beispiel vor, dass für die Methodenklasse ein Webdienst erforderlich ist.

public class UserManager {

    List<User> users;        

    public UserManager() {
        user = new LinkedLisk<User>();
    }
    
    public void addUser(User user) {
        if (isValid(user)) {
            user.add(user);
        } else {
            throw new NotValidUserException();
        }
    }
    
    protected boolean isValid(User user) {
        //some online web service to check if user is valid
    }
    
    public int numberOfUsers() {
        return users.size();
    }
}

addUser Methode muss getestet werden, um einen nützlichen Test für UserManager zu UserManager . Eine Abhängigkeit wird jedoch hier gefunden, isValid benötigt einen externen Webservice, der nicht in unserem Code enthalten ist. Dann sollte diese externe Abhängigkeit neutralisiert werden.

In diesem Fall können Sie die restlichen UserManager Methoden testen, wenn Sie nur isValid UserManager .

@Test
public void testAddUser() {
    User user = mock(User.class);
    UserManager  manager = spy(new UserManager());
    
    //it forces to manager.isValid to return true
    doReturn(true).when(manager).isValid(anyObject());
    
    manager.addUser(user);
    assertTrue(manager.numberOfUsers(), 1);
} 

Sie können das Szenario leicht überprüfen, in dem der user nicht gültig ist.

@Test(expectedExceptions = NotValidUserException.class)
public void testNotValidAddUser() {
    User user = mock(User.class);
    UserManager  manager = spy(new UserManager());
    
    //it forces to manager.isValid to return false
    doReturn(false).when(manager).isValid(anyObject());
    
    manager.addUser(user);
} 

Einfacher minimaler Mockito-Test

Dieses Beispiel zeigt einen minimalen Mockito-Test unter Verwendung einer gemockten ArrayList :

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;

import java.util.ArrayList;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;

@RunWith(MockitoJUnitRunner.class)
public class MockitoTest
{
    @Mock
    ArrayList<String> listMock;

    @Test
    public void testAppend() {
        // configure the mock to return "foobar" whenever "get()" 
        // is called on "listMock" with an int value as parameter
        doReturn("foobar").when(listMock).get(anyInt());            
        String result = listMock.get(0);
        
        assertEquals("foobar", result);
    }
}

Argumente mit ArgumentCaptor überprüfen

Verwenden Sie die ArgumentCaptor Klasse, um Argumente für auf einem Mock aufgerufene Methoden zu ArgumentCaptor . Auf diese Weise können Sie die Argumente in Ihre Testmethode extrahieren und Assertionen für sie durchführen.

In diesem Beispiel wird eine Methode getestet, mit der der Name eines Benutzers mit einer angegebenen ID aktualisiert wird. Die Methode lädt den Benutzer, aktualisiert den name Attribut mit dem angegebenen Wert und speichert sie danach. Der Test möchte überprüfen, ob das an die save Argument ein User mit der richtigen ID und dem richtigen Namen ist.

// This is mocked in the test
interface UserDao {
    void save(User user);
}

@RunWith(MockitoJUnitRunner.class)
public class UserServiceTest {
    @Mock
    UserDao userDao;

    @Test
    public void testSetNameForUser() {
        UserService serviceUnderTest = new UserService(userDao);
        
        serviceUnderTest.setNameForUser(1L, "John");

        ArgumentCaptor<User> userArgumentCaptor = ArgumentCaptor.forClass(User.class);
        
        verify(userDao).save(userArgumentCaptor.capture());
        User savedUser = userArgumentCaptor.getValue();
        assertTrue(savedUser.getId() == 1);
        assertTrue(savedUser.getName().equals("John"));
    }
}

Argumente mit ArgumentMatcher überprüfen

Mockito bietet eine Matcher<T> -Schnittstelle sowie eine abstrakte ArgumentMatcher<T> -Klasse zur Überprüfung von Argumenten. Es verwendet einen anderen Ansatz für denselben Anwendungsfall als ArgumentCaptor . Zusätzlich kann der ArgumentMatcher auch im Spott verwendet werden. In beiden Anwendungsfällen wird die Mockito.argThat() Methode verwendet, die einen einigermaßen lesbaren Mockito.argThat() bereitstellt.

verify(someMock).someMethod(Mockito.argThat(new ArgumentMatcher<String>() {
       
    @Override
    public boolean matches(Object o) {
        return o instanceof String && !((String)o).isEmpty();
    }

});        

Aus den JavaDocs von ArgumentMatcher:

Warnung: Seien Sie mit der Verwendung komplizierter Argumentvergleiche, insbesondere benutzerdefinierten Argumentvergleichern, vernünftig, da der Test dadurch weniger lesbar wird. Manchmal ist es besser, equals () für Argumente zu implementieren, die an Mocks übergeben werden (Mockito verwendet natürlich equals () zum Argumentvergleich). Dadurch kann der Test sauberer werden.

Erstellen Sie Objekte, die von Mockito verspottet werden

Es gibt zwei Möglichkeiten, ein von Mockito verspottetes Objekt zu erstellen:

  • über Annotation
  • über Mock-Funktion

Via Anmerkung:

Mit einem JUnit-Testläufer:

@RunWith(MockitoJUnitRunner.class)
public class FooTest {
    @Mock
    private Bar barMock;

    // ...
}

Sie können auch die JUnit @Rule Mockito @Rule , die dieselbe Funktionalität wie der MockitoJUnitRunner , jedoch keinen @RunWith Testläufer benötigt:

public class FooTest {
    @Rule
    public MockitoRule mockito = MockitoJUnit.rule();        

    @Mock
    private Bar barMock;

    // ...
}

Wenn Sie @RunWith oder die @Rule Annotation nicht verwenden @RunWith , können Sie auch Mocks "per Hand" @Rule :

public class FooTest {
    @Mock
    private Bar barMock;

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

    // ...
}

Über Mock-Funktion:

public class FooTest {
    private Bar barMock = Mockito.mock(Bar.class);

    // ...
}

Aufgrund der Typenlöschung können Sie eine generische Klasse nicht wie oben beschrieben simulieren. Sie müssen die Basisklasse nachahmen und explizit in den richtigen generischen Typ umwandeln:

public class FooTest {
    private Bar<String> genericBarMock = (Bar<String>) Mockito.mock(Bar.class);

    // ...
}

Fügen Sie dem gespielten Objekt ein Verhalten hinzu

Mockito.when(mock.returnSomething()).thenReturn("my val");

mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "my val" again
mock.returnSomething(); // returns "my val" again and again and again...

Wenn Sie beim zweiten Aufruf einen anderen Wert wünschen, können Sie der thenReturn-Methode das gewünschte Rückgabeargument hinzufügen:

Mockito.when(mock.returnSomething()).thenReturn("my val", "other val");

mock.returnSomething(); // returns "my val"
mock.returnSomething(); // returns "other val"
mock.returnSomething(); // returns "other val" again

Wenn Sie die Methode aufrufen, ohne dem Mock ein Verhalten hinzuzufügen, wird null zurückgegeben:

barMock.mock.returnSomethingElse(); // returns null

Falls diese Methode über Parameter verfügt, sollten Sie auch Werte angeben:

Mockito.when(mock.returnSomething("param 1")).thenReturn("my val 1");
Mockito.when(mock.returnSomething("param 2")).thenReturn("my val 2");

mock.returnSomething("param 1"); // returns "my val 1"
mock.returnSomething("param 2"); // returns "my val 2"
mock.returnSomething("param 3"); // returns null

Wenn Ihnen param Wert nicht wichtig ist, können Sie Matchers.any () verwenden:

Mockito.when(mock.returnSomething(Matchers.any())).thenReturn("p1");

mock.returnSomething("param 1"); // returns "p1"
mock.returnSomething("param other"); // returns "p1"

Um eine Ausnahme auszulösen, verwenden Sie die thenThrow-Methode:

Mockito.when(mock.returnSomething()).thenThrow(new Exception());

mock.returnSomething(); // throws Exception

Überprüfen Sie die an den Mock übergebenen Argumente

Nehmen wir an, wir haben diese Klasse und wir möchten die doSmth Methode testen. In diesem Fall wollen wir sehen, ob der Parameter "val" an foo . foo wird verspottet.

public class Bar {

    private final Foo foo;

    public Bar(final Foo foo) {
        this.foo = foo;
    }

    public void doSmth() {
        foo.bla("val");
    }
}

Dies können wir mit ArgumentCaptor :

@Mock
private Foo fooMock;

@InjectMocks
private Bar underTest;

@Captor
private ArgumentCaptor<String> stringCaptor;

@Test
public void should_test_smth() {
    underTest.doSmth();

    Mockito.verify(fooMock).bla(stringCaptor.capture());

    assertThat(stringCaptor.getValue(), is("val"));
}

Überprüfen Sie Methodenaufrufe für ein Objekt mit Objekt

Um zu überprüfen, ob eine Methode für ein Mockito.verify Objekt aufgerufen wurde, können Sie die Mockito.verify Methode verwenden:

Mockito.verify(someMock).bla();

In diesem Beispiel behaupten wir, dass die Methode bla für das someMock aufgerufen wurde.

Sie können auch überprüfen, ob eine Methode mit bestimmten Parametern aufgerufen wurde:

Mockito.verify(someMock).bla("param 1");

Wenn Sie überprüfen möchten, dass eine Methode nicht aufgerufen wurde, können Sie einen zusätzlichen Parameter für VerificationMode , verify VerificationMode zu verify :

Mockito.verify(someMock, Mockito.times(0)).bla();

Dies funktioniert auch, wenn Sie prüfen möchten, dass diese Methode mehrmals aufgerufen wurde (in diesem Fall überprüfen wir, ob die Methode bla 23 mal aufgerufen wurde):

Mockito.verify(someMock, Mockito.times(23)).bla();

Dies sind weitere Beispiele für den VerificationMode Parameter, mit denen Sie mehr Kontrolle darüber haben, wie oft eine Methode aufgerufen werden muss:

Mockito.verify(someMock, Mockito.never()).bla(); // same as Mockito.times(0)

Mockito.verify(someMock, Mockito.atLeast(3)).bla(); // min 3 calls

Mockito.verify(someMock, Mockito.atLeastOnce()).bla(); // same as Mockito.atLeast(1)

Mockito.verify(someMock, Mockito.atMost(3)).bla(); // max 3 calls

Stubbing void Methoden

void Methoden können mithilfe der Methodenfamilie doThrow () , doAnswer () , doNothing () , doCallRealMethod () unterbunden werden.

Runnable mock = mock(Runnable.class);

doThrow(new UnsupportedOperationException()).when(mock).run();

mock.run(); // throws the UnsupportedOperationException

Beachten Sie, dass void Methoden nicht mit einem Stubben versehen werden können, when(..) der Compiler keine void Methoden als Argument mag.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow