Szukaj…


Uwagi

Mockito to frameworki Jock, które mają na celu zapewnienie możliwości pisania czystych, czytelnych testów jednostkowych przy użyciu prostego interfejsu API. Różni się od innych fałszywych frameworków tym, że pozostawia wzorzec „oczekuj-uruchom-zweryfikuj”, z którego korzysta większość innych frameworków.

Zamiast tego zna tylko jeden sposób na kpowanie (nie-końcowe) klasy i interfejsy oraz pozwala na weryfikację i odgałęzienie na podstawie elastycznych dopasowań argumentów.

Obecną wersję 1.10.19 najlepiej uzyskać przy pomocy maven

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

lub stopień

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

Wersja 2 jest wciąż w fazie beta.

Wersje

Wersja Maven Central Informacje o wydaniu Data wydania
2.1.0 mockito-core zmiany 04.10.2016
1.10.19 mockito-core zmiany 31.12.2014

Prosty test jednostkowy przy użyciu Mockito

Klasa, którą będziemy testować to:

public class Service {

    private Collaborator collaborator;

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

Jego współpracownikiem jest:

public class Collaborator {

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

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

}

W naszym teście chcemy przełamać zależność od Collaborator i jego błędów, więc zamierzamy wyśmiewać Collaborator :

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

Korzystanie z adnotacji Mockito

Klasa, którą będziemy testować to:

public class Service{

    private Collaborator collaborator;

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

Jego współpracownikiem jest:

public class Collaborator {

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

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

}

W naszym teście chcemy przełamać zależność od Collaborator i jego błędów, więc zamierzamy kpić z Collaborator . Korzystanie z adnotacji @Mock jest wygodnym sposobem tworzenia różnych instancji prób dla każdego testu:

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 spróbuje rozwiązać wstrzyknięcie zależności w następującej kolejności:

  1. Zastrzyk oparty na konstruktorze - do konstruktora wstrzykuje się większość argumentów (jeśli nie można znaleźć niektórych argumentów, przekazywane są wartości null). Jeśli obiekt został pomyślnie utworzony za pomocą konstruktora, nie zostaną zastosowane żadne inne strategie.
  2. Zastrzyk na bazie setera - próbki są wstrzykiwane według rodzaju. Jeśli istnieje kilka właściwości tego samego typu, zostaną dopasowane nazwy właściwości i imiona.
  3. Bezpośredni wtrysk w polu - taki sam jak w przypadku wtrysku na bazie setera.

Należy pamiętać, że awaria nie jest zgłaszana w przypadku niepowodzenia którejkolwiek z wyżej wymienionych strategii.

Proszę zapoznać się z najnowszymi @InjectMocks Bardziej szczegółowe informacje na temat tego mechanizmu w najnowszej wersji Mockito.

Instalacja i konfiguracja

Instalacja

Preferowanym sposobem instalacji Mockito jest zadeklarowanie zależności od mockito-core z wybranym systemem kompilacji. Według stanu na 22 lipca 2016 r. Najnowszą wersją inną niż beta jest wersja 1.10.19, ale migracja do wersji 2.x jest już zalecana.

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.+" }

Istnieje również mockito-all które zawiera Hamcrest i Objenesis oprócz samego Mockito. Jest dostarczany przez Maven głównie dla użytkowników mrówek, ale dystrybucja została przerwana w Mockito 2.x.


Import

Większość funkcji Mockito to statyczne metody org.mockito.Mockito . W ten sposób Mockito można statycznie zaimportować do klasy w następujący sposób:

import static org.mockito.Mockito.*;

Punkt wejścia dokumentacji znajduje się w javadoc tej klasy.

Wyśmiewać niektóre metody z obiektu

Tylko niektóre metody obiektu można wyśmiewać za pomocą spy() z mockito.

Wyobraź sobie na przykład, że klasa metod wymaga pewnych usług sieciowych do działania.

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

Metoda addUser musi zostać przetestowana, aby wykonać użyteczny test dla UserManager . Znajduje się tu jednak zależność, isValid wymaga zewnętrznej usługi internetowej, która nie jest zawarta w naszym kodzie. Następnie tę zewnętrzną zależność należy zneutralizować.

W takim przypadku, jeśli tylko isValid , będziesz mógł przetestować pozostałe metody 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);
} 

Możesz łatwo sprawdzić scenariusz, w którym user jest nieprawidłowy.

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

Prosty minimalny test Mockito

Ten przykład pokazuje minimalny test Mockito przy użyciu fałszywej 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);
    }
}

Weryfikacja argumentów za pomocą ArgumentCaptor

Aby sprawdzić poprawność argumentów w metodach wywoływanych na próbce, użyj klasy ArgumentCaptor . Umożliwi to wyodrębnienie argumentów do metody testowej i wykonanie na nich asercji.

W tym przykładzie przetestowano metodę, która aktualizuje nazwę użytkownika o danym identyfikatorze. Metoda ładuje użytkownika, aktualizuje atrybut name podaną wartością i zapisuje go później. Test chce upewnić się, że argument przekazany do save metody jest User obiekt z prawidłowym ID i nazwę.

// 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"));
    }
}

Weryfikacja argumentów za pomocą ArgumentMatcher

Mockito zapewnia interfejs Matcher<T> wraz z abstrakcyjną klasą ArgumentMatcher<T> do weryfikacji argumentów. Używa innego podejścia do tego samego przypadku użycia niż ArgumentCaptor . Dodatkowo ArgumentMatcher może być również używany w kpinach. Oba przypadki użycia wykorzystują metodę Mockito.argThat() , która zapewnia czytelny kod testowy.

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

});        

Z JavaDocs ArgumentMatcher:

Ostrzeżenie: bądź rozsądny, używając skomplikowanego dopasowywania argumentów, zwłaszcza niestandardowych dopasowań argumentów, ponieważ może to spowodować, że test będzie mniej czytelny. Czasami lepiej jest zaimplementować equals () dla argumentów przekazywanych do prób (Mockito naturalnie używa equals () do dopasowywania argumentów). To może uczynić test czystszym.

Twórz obiekty wyśmiewane przez Mockito

Istnieją dwa sposoby tworzenia obiektu wyśmiewanego przez Mockito:

  • za pomocą adnotacji
  • poprzez funkcję makiety

Za pomocą adnotacji:

Z programem testującym JUnit:

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

    // ...
}

Możesz także użyć JUnit @Rule , który zapewnia taką samą funkcjonalność jak MockitoJUnitRunner , ale nie wymaga @RunWith testera:

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

    @Mock
    private Bar barMock;

    // ...
}

Jeśli nie można użyć @RunWith lub @Rule adnotacji można również init mocks „za rękę”:

public class FooTest {
    @Mock
    private Bar barMock;

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

    // ...
}

Poprzez funkcję makiety:

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

    // ...
}

Z powodu wymazywania typu nie można kpić z ogólnej klasy, jak wyżej. Musisz wyśmiewać klasę podstawową i jawnie rzutować na odpowiedni typ ogólny:

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

    // ...
}

Dodaj zachowanie do wyśmiewanego obiektu

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...

Jeśli chcesz mieć inną wartość przy drugim wywołaniu, możesz dodać żądany argument powrotu do metody thenReturn:

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

Jeśli wywołasz metodę bez dodawania zachowania do próby, zwróci null:

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

W przypadku, gdy próbowana metoda ma parametry, należy również zadeklarować wartości:

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

Jeśli nie zależy ci na wartości parametru, możesz użyć Matchers.any ():

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

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

Aby zgłosić wyjątek, użyj metody thenThrow:

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

mock.returnSomething(); // throws Exception

Sprawdź argumenty przekazane próbnemu

Załóżmy, że mamy tę klasę i chcielibyśmy przetestować metodę doSmth . W tym przypadku chcemy sprawdzić, czy parametr „val” jest przekazywany do foo . Obiekt foo jest wyśmiewany.

public class Bar {

    private final Foo foo;

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

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

Możemy to osiągnąć za pomocą 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"));
}

Sprawdź wywołania metod na wyśmiewanym obiekcie

Aby sprawdzić, czy metoda została wywołana na Mockito.verify obiekcie, możesz użyć metody Mockito.verify :

Mockito.verify(someMock).bla();

W tym przykładzie twierdzimy, że metoda bla została wywołana na obiekcie someMock .

Możesz także sprawdzić, czy metoda została wywołana z określonymi parametrami:

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

Jeśli chcesz sprawdzić, czy metoda nie została wywołana, możesz przekazać dodatkowy parametr VerificationMode , aby verify :

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

Działa to również, jeśli chcesz sprawdzić, czy ta metoda została wywołana więcej niż jeden raz (w tym przypadku sprawdzamy, że metoda bla została wywołana 23 razy):

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

Oto więcej przykładów parametru VerificationMode , zapewniających większą kontrolę nad liczbą wywołań metody:

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

Stubbingowe metody pustki

Metody void można stubować przy użyciu metod z rodziny doThrow () , doAnswer () , doNothing () , doCallRealMethod () .

Runnable mock = mock(Runnable.class);

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

mock.run(); // throws the UnsupportedOperationException

Zauważ, że nie można void metod void when(..) powoduje, że kompilator nie lubi metod void jako argumentu.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow