Mocking met Mockito

January 5th, 2013 | 5 min read | JUnit, Mockito, Spring, Testing

In de vorige tutorial heb ik gesproken over JUnit en heb ik hier en daar het woord “mocking” aangehaald. Stel je hebt een controller die een DAO service aanroept (zoals we eerder al gezien hebben), als we tests voor deze controller gaan schrijven willen we niet dat alle achterliggende lagen tevens aangeroepen worden.
Het zou namelijk totaal niet performant zijn om als we de controller wensen te testen, allerlei data gaan wegschrijven in de database en daarna zelfs de staat van onze entiteiten en waarschijnlijk ook ons testresultaat veranderen.Dankzij polymorfisme kunnen we dat echter snel verhelpen, stel dat de controller een veld heeft van het type DAOService waar we normaal onze implementatie in plaatsen en we dat tijdens de tests nu zouden vervangen door een test implementatie (die gewoon wat dummy resultaten geeft), dan garanderen we dat de achterliggende lagen niet aangeroepen worden en dat na het uitvoeren van de tests de staat steeds hetzelfde blijft (we geven namelijk steeds dezelfde dummy gegevens terug).

Deze aanpak is heel mooi, maar soms is het gewoon niet wenselijk om een hele test implementatie te schrijven of is het zelfs gewoonweg onmogelijk omdat er geen sprake is van een interface/polymorfisme. In deze gevallen zijn mocking frameworks zoals Mockito je beste vriend.

Heads up!

In deze tutorial wordt met regelmaat verwezen naar mijn vorige Java tutorials. Het is dus handig dat je deze (zeker de eerste) eens doorneemt.

Project opzetten

In dit project ga ik verder gaan op basis van waar we de laatste keer in Spring & JUnit gestopt zijn. Kopieer dus de code die je onderaan de tutorial kan downloaden en hernoem deze indien gewenst.

Maven configuratie

Als we het over frameworks hebben, hebben we het uiteraard ook over dependencies.  De dependency die je moet toevoegen om met mockito te kunnen werken is:

<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.9.5</version>
    <scope>test</scope>
</dependency>

Zoals je kan zien heeft deze net zoals in de voorgaande tutorial ook een test-scope wat wilt zeggen dat deze dependency enkel gebruikt wordt om te testen en niet als library in de WAR wordt geplaatst.

Test case aanpassen

Bovenaan

FormControllerTest

plaatsen we de volgende import:

import static org.mockito.Mockito.*;

Deze import bevat allerlei extra functies die Mockito beschikbaar stelt.

De volgende stap is dat we de

ModelMap

gaan mocken, wijzig hiervoor de methode

setUp()

door:

@Before
public void setUp() throws Exception {
    model = mock(ModelMap.class);
}

Zoals je kan zien komt hier het keyword

new

niet meer aan te pas, we maken dus geen object meer aan, maar laten mockito een mock object maken. Dit gaat onze werkwijze wel iets aanpassen, we zullen dus ook enkele tests moeten aanpassen.

De methode

testPostFormBean()

wijzig je door:

@Test
public void testPostFormBean() {
    Text text = mock(Text.class);
    when(text.getTekst()).thenReturn("test");

    assertEquals("result", controller.postFormBean(text, null, model));
    verify(text).getTekst();
    verify(model).addAttribute("tekst", "test");
}

Zoals je kan zien maken we ook een mock object aan van de

Text

-class (omdat het kan). We kunnen nu natuurlijk niet meer verwachten dat deze mock class zelf een goede waarde gaat geven voor alle methodes, mock objecten hebben namelijk geen staat. Dit moeten we zelf doen door middel van

when(text.getTekst()).thenReturn("test");

.
Wat we hier eigenlijk zeggen is dat als iemand de methode

getTekst()

oproept op het mock object, dan returnen we

"test"

.

Omdat deze objecten geen staat hebben, kunnen we tevens niet zomaar controleren of het model wel de juiste attributen bevat. Neen, wat we wel kunnen controleren is of een bepaalde methode van het mock-object opgeroepen is, met welke parameters en zelfs hoe vaak (de mogelijkheden zijn enorm).
Dit doe je met de

verify()

opdracht, bijvoorbeeld:

verify(model).addAttribute("tekst", "test");

.
Hierin staat eigenlijk dat we verifiëren of de methode

addAttribute()

aangeroepen is met die bepaalde parameters, zo niet, faalt de test.

Ook de methode

testPostFormEasy()

kunnen we aanpassen en gebruik maken van mocks. We krijgen dan de volgende code:

@Test
public void testPostFormEasy() {
    assertEquals("result", controller.postFormEasy("test", model));
    verify(model).addAttribute("tekst", "test");
}

Deze methode is iets eenvoudiger dan de voorgaande, het enige wat we hier doen is verifiëren of de methode

addAttribute()

wel aangeroepen is met de juiste parameters.

Builden

Eenmaal de test case aangepast zijn we klaar met deze (vrij korte) tutorial. Je kan nu de tests runnen met het commando:

mvn clean install -DskipTests=false

of via Eclipse zelf.

junit-eclipse-result

Download project

Download – mockito-example.rar (5,9 kB)

Back to tutorialsContact me on TwitterDiscuss on Twitter

Profile picture

Dimitri "g00glen00b" Mestdagh is a consultant at Cronos and tech lead at Aquafin. Usually you can find him trying out new libraries and technologies. Loves both Java and JavaScript.