Sök…


Anmärkningar

Mockito är ett java Mocking-ramverk som syftar till att tillhandahålla förmågan att skriva rent en läsbar enhetstest med hjälp av det enkla API. Det skiljer sig från andra hålande ramverk genom att lämna det förväntade körningsverifieringsmönstret som de flesta andra ramverk använder.

Istället vet det bara ett sätt att håna (icke-slutliga) klasser och gränssnitt och tillåter att verifiera och stoppa baserat på flexibla argumentmatchare.

Den nuvarande version 1.10.19 erhålls bäst med maven

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

eller gradle

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

Version 2 finns fortfarande i beta.

versioner

Version Maven Central Släppanteckningar Utgivningsdatum
2.1.0 Mockito-core ändringar 2016/10/04
1.10.19 Mockito-core ändringar 2014/12/31

Enkelt enhetstest med Mockito

Klassen vi ska testa är:

public class Service {

    private Collaborator collaborator;

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

Dess samarbetspartner är:

public class Collaborator {

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

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

}

I vårt test vill vi bryta beroendet från Collaborator och dess buggar, så vi kommer att håna 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);
    }  
}

Använda Mockito-kommentarer

Klassen vi ska testa är:

public class Service{

    private Collaborator collaborator;

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

Dess samarbetspartner är:

public class Collaborator {

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

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

}

I vårt test vill vi bryta beroendet från Collaborator och dess buggar, så vi kommer att håna Collaborator . Att använda @Mock kommentarer är ett bekvämt sätt att skapa olika instanser av håravfall för varje test:

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 försöker lösa beroendeinjektion i följande ordning:

  1. Konstruktorbaserad injektion - hårav sprutas in i konstruktören med de flesta argument (om vissa argument inte kan hittas, då passas nollor). Om ett objekt skapades med framgång via konstruktör kommer inga andra strategier att tillämpas.
  2. Seterbaserad injektion - håravfall injiceras efter typ. Om det finns flera egenskaper av samma typ, kommer egenskapens namn och hånappningar att matchas.
  3. Direktfältinsprutning - samma som för setterbaserad injektion.

Observera att inget fel rapporteras i fallet om någon av de nämnda strategierna misslyckades.

Se de senaste @InjectMocks för mer detaljerad information om denna mekanism i den senaste versionen av Mockito.

Installation och installation

Installation

Det föredragna sättet att installera Mockito är att förklara ett beroende av mockito-core med ett valfritt byggsystem. Från och med 22 juli 2016 är den senaste versionen som inte är beta-version 1.10.19, men 2.x uppmuntras redan att migreras till .

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

Det finns också mockito-all som innehåller Hamcrest och Objenesis förutom Mockito själv. Det levereras via Maven huvudsakligen för myranvändare, men distributionen har avbrutits i Mockito 2.x.


Importera

De flesta av Mockito-anläggningarna är statiska metoder för org.mockito.Mockito . Således kan Mockito statiskt importeras till en klass på detta sätt:

import static org.mockito.Mockito.*;

Dokumentationspost finns i javadoc för denna klass.

Hånga vissa metoder på ett objekt

Bara vissa metoder för ett objekt kan hånas med spy() av mockito.

Föreställ dig till exempel att metodklassen kräver viss webbtjänst för att fungera.

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 metoden måste testas för att göra ett användbart test för UserManager . Men ett beroende finns här, isValid kräver en extern webbtjänst som inte finns i vår kod. Därefter bör detta yttre beroende neutraliseras.

Om du bara hånar isValid du testa resten av UserManager metoderna.

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

Du kan enkelt kontrollera scenariot där user inte är giltig.

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

Enkelt minimalt Mockito-test

Detta exempel visar ett minimalt Mockito-test med en hånad 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);
    }
}

Verifiera argument med ArgumentCaptor

ArgumentCaptor klassen ArgumentCaptor att validera argument till metoder som kallas för en håna. Detta gör att du kan extrahera argumenten i din testmetod och utföra påståenden om dem.

Detta exempel testar en metod som uppdaterar namnet på en användare med ett givet ID. Metoden laddar användaren uppdaterar name attribut med det givna värdet och sparar det efteråt. Testet vill kontrollera att argumentet skickas till save metoden är en User med rätt ID och namn.

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

Verifiera argument med ArgumentMatcher

Mockito tillhandahåller ett Matcher<T> gränssnitt tillsammans med en abstrakt ArgumentMatcher<T> klass för att verifiera argument. Den använder en annan metod för samma användningsfall än ArgumentCaptor . Dessutom kan ArgumentMatcher också användas för att håna. Båda användningsfallen använder sig av Mockito.argThat() -metoden som ger en rimligt läsbar testkod.

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

});        

Från JavaDocs of ArgumentMatcher:

Varning: Var rimlig med att använda komplicerade argumentmatchningar, särskilt anpassade argumentmatare, eftersom det kan göra testet mindre läsbart. Ibland är det bättre att implementera lika () för argument som skickas till mock (Mockito använder naturligtvis lika () för argumentmatchning). Detta kan göra testet renare.

Skapa objekt hånade av Mockito

Det finns två sätt att skapa objekt som hånats av Mockito:

  • via annotering
  • via mock-funktion

Via en kommentar:

Med en JUnit-testlöpare:

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

    // ...
}

Du kan också använda Mockitos JUnit @Rule , som ger samma funktionalitet som MockitoJUnitRunner , men behöver inte en @RunWith :

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

    @Mock
    private Bar barMock;

    // ...
}

Om du inte kan använda @RunWith eller @Rule anteckningen kan du också initta skott "per hand":

public class FooTest {
    @Mock
    private Bar barMock;

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

    // ...
}

Via mock-funktion:

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

    // ...
}

På grund av radering av typen kan du inte håna en generisk klass som ovan. Du måste håna basklassen och uttryckligen kasta till rätt generisk typ:

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

    // ...
}

Lägg till beteende till det hånade objektet

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

Om du vill ha annat värde på det andra samtalet kan du lägga till önskat returargument till thenReturn-metoden:

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

Om du kommer att ringa metoden utan att lägga till beteende till håna kommer den att returnera noll:

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

Om den hånade metoden har parametrar bör du också ange värden:

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

Om du inte bryr dig om paramvärdet kan du använda Matchers.any ():

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

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

För att kasta undantag använder du sedanTrowrow-metoden:

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

mock.returnSomething(); // throws Exception

Kontrollera argument som skickats till håna

Låt oss anta att vi har den här klassen och vi vill testa doSmth metoden. I det här fallet vill vi se om parameter "val" skickas till foo . Objekt foo hånas.

public class Bar {

    private final Foo foo;

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

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

Vi kan uppnå detta med 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"));
}

Verifiera metodsamtal på hånligt objekt

För att kontrollera om en metod kallades på ett hånat objekt kan du använda metoden Mockito.verify :

Mockito.verify(someMock).bla();

I det här exemplet hävdar vi att metoden bla kallades på someMock .

Du kan också kontrollera om en metod har anropats med vissa parametrar:

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

Om du vill kontrollera att en metod inte kallades kan du skicka en ytterligare VerificationMode parameter för att verify :

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

Detta fungerar också om du vill kontrollera att den här metoden kallades mer än en gång (i detta fall kontrollerar vi att metoden bla heter 23 gånger):

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

Dessa är fler exempel på VerificationMode parametern, vilket ger mer kontroll över antalet gånger en metod bör kallas:

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 metoder

void kan stoppas med hjälp av doThrow () , doAnswer () , doNothing () , doCallRealMethod () -familjens metoder.

Runnable mock = mock(Runnable.class);

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

mock.run(); // throws the UnsupportedOperationException

Observera att void metoder inte kan stoppas med when(..) orsakar att kompilatorn inte gillar void som argument.



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow