JUnit & Mockito, first steps

55
JUnit & Mockito, First steps @QuadraticBE Jul. 2014

description

JUnit & Mockito, first steps

Transcript of JUnit & Mockito, first steps

Page 1: JUnit & Mockito, first steps

JUnit & Mockito,First steps

@QuadraticBEJul. 2014

Page 2: JUnit & Mockito, first steps

So it’s done...

I’m Renato Primavera from Quadratic

I write software that helps customers to manage and make use of their geographical data

@RenatoPrimavera [email protected]

www.quadratic.be

Page 3: JUnit & Mockito, first steps

Let’s start with

JUnit

Page 4: JUnit & Mockito, first steps

JUnit is a programmer-oriented

testing framework for Java

It is a simple framework to write repeatable tests

Page 5: JUnit & Mockito, first steps

JUnit is linked as a JAR at compile-time

The framework resides under package org.junit for JUnit 4 and later

Page 6: JUnit & Mockito, first steps

<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>

... </dependencies>

in thePOM

It’s really simple to integrate JUnit in your Maven Project

Page 7: JUnit & Mockito, first steps

If not using Maven,all you need is to add 2 JARs

on your test classpath

- junit.jar- hamcrest-core.jar

Page 8: JUnit & Mockito, first steps

JUnit is based on Java annotations

@[email protected]@[email protected]@org.junit.After

Page 9: JUnit & Mockito, first steps

import org.junit.*; public class TestFoobar {

}

Let’s start a JUnit Test Case

Page 10: JUnit & Mockito, first steps

@BeforeClasspublic static void setUpClass() throws Exception { // Code executed before the first test method } @Beforepublic void setUp() throws Exception { // Code executed before each test }

It’s possible to define some test context (called “Test Fixture”), before (“setUp”)...

Page 11: JUnit & Mockito, first steps

@AfterClasspublic static void tearDownClass() throws Exception { // Code executed after the last test method }

@Afterpublic void tearDown() throws Exception { // Code executed after each test }

...and after (“tearDown”)...

Page 12: JUnit & Mockito, first steps

@Testpublic void testOneThing() {

// Code that tests one thing}

@Testpublic void testAnotherThing() {

// Code that tests another thing}

Now you’re ready to write tests themselves

Page 13: JUnit & Mockito, first steps

> Assertions (and Matchers…)

Page 14: JUnit & Mockito, first steps

JUnit provides assertion methods for all primitive types and Objects and arrays

The parameter order is “expected value” followed by “actual value”

Optionally the first parameter can be a String message that is output on failure

Page 15: JUnit & Mockito, first steps

import static org.junit.Assert.*;

assertEquals("failure - strings not equal", "text", "text");

assertFalse("failure - should be false", false);

assertSame("should be same", aNumber, aNumber);

assertArrayEquals("failure - byte arrays not same", expected,

actual);

Page 16: JUnit & Mockito, first steps

There is a slightly different assertion, “assertThat” that

takes a Matcher object

Page 17: JUnit & Mockito, first steps

import static org.junit.Assert.*;

import static org.junit.matchers.JUnitMatchers.*;

assertThat("albumen", both(containsString("a")).and

(containsString("b")));

assertThat(Arrays.asList("one", "two", "three"), hasItems

("one", "three"));

assertThat(Arrays.asList(new String[] { "fun", "ban", "net"

}), everyItem(containsString("n")));

Page 18: JUnit & Mockito, first steps

Note that expected and actual are reversed compared to the

other assert methods...

Page 19: JUnit & Mockito, first steps

assertThat can also be used with

Hamcrest MatchersHamcrest Provides a library of matcher objects (also known as constraints or predicates) allowing 'match' rules to be defined declaratively, to be used in other

frameworks

Hamcrest it is not a testing library: it just happens that matchers are very useful for testing

Page 20: JUnit & Mockito, first steps

import static org.junit.Assert.*;

import static org.hamcrest.CoreMatchers.*;

assertThat("good", allOf(equalTo("good"), startsWith

("good")));

assertThat("good", anyOf(equalTo("bad"), equalTo("good")));

assertThat(7, not(CombinableMatcher.<Integer> either(equalTo

(3)).or(equalTo(4))));

assertThat(new Object(), not(sameInstance(new Object())));

Page 21: JUnit & Mockito, first steps

> Test Suites(how to aggregate tests)

Page 22: JUnit & Mockito, first steps

Using Suite as a runner allows you to manually build a suite containing tests from

many classes

Page 23: JUnit & Mockito, first steps

To use it, annotate a class with @RunWith(Suite.class) and

@SuiteClasses(TestClass1.class, ...)

When you run this class, it will run all the tests in all the suite classes

Page 24: JUnit & Mockito, first steps

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

@RunWith(Suite.class)

@Suite.SuiteClasses({

TestFeatureLogin.class, TestFeatureLogout.class,

TestFeatureNavigate.class, TestFeatureUpdate.class

})

public class FeatureTestSuite {

// the class remains empty,

// used only as a holder for the above annotations

}

Page 25: JUnit & Mockito, first steps

> Miscellaneous

Page 26: JUnit & Mockito, first steps

Use JUnitCore to run tests and see the results on the console

> java org.junit.runner.JUnitCore TestClass1 [...other

test classes...]

Both your test class and junit must be on the classpath

Page 27: JUnit & Mockito, first steps

If using Maven, just execute

> mvn test

...and the Surefire plugin of Maven will execute all JUnit tests under

src/test/java

Page 28: JUnit & Mockito, first steps

The tests execution reportis then available in

target/surefire-reports

<?xml version="1.0" encoding="UTF-8" ?><testsuite failures="0" time="0.015" errors="0" skipped="0" tests="1" name="com.mycompany.app.AppTest"> <properties> ... </properties> <testcase time="0.002" classname="com.mycompany.app.AppTest" name="testApp"/></testsuite>

Page 29: JUnit & Mockito, first steps

If for some reason, you don't want a test to fail, you just want

it ignored, you temporarily disable a test

@Ignore("Test is ignored as a demonstration")

@Test

public void testSane() {

assertThat(1, is(1));

}

Page 30: JUnit & Mockito, first steps

Tests that 'runaway' or take too long, can be automatically failed

There are two options for implementing timeout

Page 31: JUnit & Mockito, first steps

Timeout parameter on @Test Annotation (applies to test method)

@Test(timeout=1000)public void testWithTimeout() { ...}

#1

Page 32: JUnit & Mockito, first steps

Timeout Rule (applies to entire test class)

public class HasGlobalTimeout { @Rule public Timeout globalTimeout = new Timeout(10000); // 10 seconds max per method tested @Test public void testInfiniteLoop{ … }}

#2

Page 33: JUnit & Mockito, first steps

OK for JUnitLet’s see

now...

Page 34: JUnit & Mockito, first steps

Mockito is a Java framework allowing the creation of

test double objects (mock objects) in automated

unit tests

Page 35: JUnit & Mockito, first steps

Test Double is a generic term for any case where you replace a production object for testing purposes

Page 36: JUnit & Mockito, first steps

Why mocking?

Some “real” objects required in Unit tests are really complex to instanciate and/or configure

Sometimes, only interfaces exist, implementations are not even coded

Page 37: JUnit & Mockito, first steps

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

... </dependencies>

in thePOM

It’s really simple to integrate Mockito in your Maven Project

Page 38: JUnit & Mockito, first steps

Now we can verify interactions through mock objects

//Let's import Mockito statically so that the code looks clearer import static org.mockito.Mockito.*; //mock creation List mockedList = mock(List.class);

//using mock object mockedList.add("one"); mockedList.clear();

//verification verify(mockedList).add("one"); verify(mockedList).clear();

Page 39: JUnit & Mockito, first steps

Once created, mock will remember all interactions

Then you can selectively verify whatever interaction you are

interested in

Page 40: JUnit & Mockito, first steps

By default, for all methods that return value, mock returns null, an empty collection or appropriate primitive/primitive wrapper value

(e.g: 0, false, ...)

But wait!

Page 41: JUnit & Mockito, first steps

This is where stubbing comes

//You can mock concrete classes, not only interfaces LinkedList mockedList = mock(LinkedList.class); //stubbing when(mockedList.get(0)).thenReturn("first"); when(mockedList.get(1)).thenThrow(new RuntimeException()); //following prints "first" System.out.println(mockedList.get(0)); //following throws runtime exception System.out.println(mockedList.get(1)); //following prints "null" because get(999) was not stubbed System.out.println(mockedList.get(999));

Page 42: JUnit & Mockito, first steps

Mockito verifies argument values in natural java style: by using an equals() method

Sometimes, when extra flexibility is required then you might use

argument matchers

Page 43: JUnit & Mockito, first steps

//stubbing using built-in anyInt() argument matcherwhen(mockedList.get(anyInt())).thenReturn("element");

//stubbing using hamcrest (let's say isValid() //returns your own hamcrest matcher):when(mockedList.contains(argThat(isValid()))).thenReturn("element");

//you can also verify using an argument matcherverify(mockedList).get(anyInt());

Here are some argument matchers

Page 44: JUnit & Mockito, first steps

verify(mock).someMethod(anyInt(), anyString(), eq("third argument"));//above is correct - eq() is also an argument matcher

verify(mock).someMethod(anyInt(), anyString(), "third argument");//above is incorrect - exception will be thrown because third argument is //given without an argument matcher

Note that if you are using argument matchers, all arguments have to be provided by matchers

Page 45: JUnit & Mockito, first steps

Verifying exact number of invocations / at least x / never

//exact number of invocations verificationverify(mockedList, times(2)).add("twice");verify(mockedList, times(3)).add("three times"); //verification using never(). never() is an alias to times(0)verify(mockedList, never()).add("never happened"); //verification using atLeast()/atMost()verify(mockedList, atLeastOnce()).add("three times");verify(mockedList, atLeast(2)).add("five times");verify(mockedList, atMost(5)).add("three times");

Page 46: JUnit & Mockito, first steps

Verification in orderSingle mock whose methods must be invoked in

a particular order

List singleMock = mock(List.class);

//using a single mocksingleMock.add("was added first");singleMock.add("was added second"); //create an inOrder verifier for a single mockInOrder inOrder = inOrder(singleMock); //following will make sure that add is first called with "was added first, //then with "was added second"inOrder.verify(singleMock).add("was added first");inOrder.verify(singleMock).add("was added second");

Page 47: JUnit & Mockito, first steps

Verification in orderMultiple mocks that must be used in a particular order

List firstMock = mock(List.class);List secondMock = mock(List.class);

//using mocksfirstMock.add("was called first");secondMock.add("was called second");

//create inOrder object passing any mocks that need to be verified in orderInOrder inOrder = inOrder(firstMock, secondMock);

//following will make sure that firstMock was called before secondMockinOrder.verify(firstMock).add("was called first");inOrder.verify(secondMock).add("was called second");

Page 48: JUnit & Mockito, first steps

Sometimes we need to stub with different return value/exception

for the same method call, we need to stub consecutive calls (iterator-

style stubbing)

Page 49: JUnit & Mockito, first steps

when(mock.someMethod("some arg")) .thenThrow(new RuntimeException()) .thenReturn("foo"); //First call: throws runtime exception:mock.someMethod("some arg"); //Second call: prints "foo"System.out.println(mock.someMethod("some arg")); //Any consecutive call: prints "foo" as well (last stubbing wins).System.out.println(mock.someMethod("some arg"));

Alternative, shorter version of consecutive stubbing

when(mock.someMethod("some arg")) .thenReturn("one", "two", "three");

Page 50: JUnit & Mockito, first steps

It’s also possible to create spies of real objects

When you use the spy then the real methods are called

(unless a method was stubbed)

Page 51: JUnit & Mockito, first steps

List list = new LinkedList();List spy = spy(list);

//optionally, you can stub out some methods:when(spy.size()).thenReturn(100); //using the spy calls *real* methodsspy.add("one");spy.add("two"); //prints "one" - the first element of a listSystem.out.println(spy.get(0)); //size() method was stubbed - 100 is printedSystem.out.println(spy.size()); //optionally, you can verifyverify(spy).add("one");verify(spy).add("two");

Page 52: JUnit & Mockito, first steps

So if you keep the real instance and interact with it, don't expect the spied to be aware of those interaction and their

effect on real instance state

The corollary is that when an unstubbed method is called on the spy but not on the real instance, you won't see any

effects on the real instance

To know when spying real objects!

Mockito does not delegate calls to the passed real instance, instead it actually creates a copy of it

Page 53: JUnit & Mockito, first steps

Capturing arguments for further assertions with ArgumentCaptor

//create the ArgumentCaptor for class PersonArgumentCaptor<Person> argument = ArgumentCaptor.forClass(Person.class);

//verify that the doSomething method of the mock object was called //with a Person argument verify(mock).doSomething(argument.capture());

//assert that the name of that Person argument was “John” Person person = argument.getValue();assertEquals("John", person.getName());

Page 55: JUnit & Mockito, first steps

Thanks