mockito Tutorial
Erste Schritte mit Mockito
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:
- 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.
- Setter-basierte Injektion - Mocks werden nach Typ eingespritzt. Wenn mehrere Eigenschaften desselben Typs vorhanden sind, werden die Eigenschaftsnamen und die Modellnamen abgeglichen.
- 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.