JUnit & Mockito, first steps

3,924 views

Published on

JUnit & Mockito, first steps

Published in: Software
1 Comment
9 Likes
Statistics
Notes
  • for slide 49, if I want first call to do something else (say create a new arrayList()) and second call to call somemethod() then ?
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Views
Total views
3,924
On SlideShare
0
From Embeds
0
Number of Embeds
24
Actions
Shares
0
Downloads
223
Comments
1
Likes
9
Embeds 0
No embeds

No notes for slide

JUnit & Mockito, first steps

  1. 1. JUnit & Mockito, First steps @QuadraticBEJul. 2014
  2. 2. 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 renato.primavera@quadratic.be www.quadratic.be
  3. 3. Let’s start with JUnit
  4. 4. JUnit is a programmer-oriented testing framework for Java It is a simple framework to write repeatable tests
  5. 5. JUnit is linked as a JAR at compile-time The framework resides under package org.junit for JUnit 4 and later
  6. 6. <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
  7. 7. If not using Maven, all you need is to add 2 JARs on your test classpath - junit.jar - hamcrest-core.jar
  8. 8. JUnit is based on Java annotations @org.junit.Test @org.junit.BeforeClass @org.junit.Before @org.junit.AfterClass @org.junit.After
  9. 9. import org.junit.*; public class TestFoobar { } Let’s start a JUnit Test Case
  10. 10. @BeforeClass public static void setUpClass() throws Exception { // Code executed before the first test method } @Before public void setUp() throws Exception { // Code executed before each test } It’s possible to define some test context (called “Test Fixture”), before (“setUp”)...
  11. 11. @AfterClass public static void tearDownClass() throws Exception { // Code executed after the last test method } @After public void tearDown() throws Exception { // Code executed after each test } ...and after (“tearDown”)...
  12. 12. @Test public void testOneThing() { // Code that tests one thing } @Test public void testAnotherThing() { // Code that tests another thing } Now you’re ready to write tests themselves
  13. 13. > Assertions (and Matchers…)
  14. 14. 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
  15. 15. 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);
  16. 16. There is a slightly different assertion, “assertThat” that takes a Matcher object
  17. 17. 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")));
  18. 18. Note that expected and actual are reversed compared to the other assert methods...
  19. 19. assertThat can also be used with Hamcrest Matchers Hamcrest 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
  20. 20. 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())));
  21. 21. > Test Suites (how to aggregate tests)
  22. 22. Using Suite as a runner allows you to manually build a suite containing tests from many classes
  23. 23. 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
  24. 24. 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 }
  25. 25. > Miscellaneous
  26. 26. 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
  27. 27. If using Maven, just execute > mvn test ...and the Surefire plugin of Maven will execute all JUnit tests under src/test/java
  28. 28. The tests execution report is 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>
  29. 29. 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)); }
  30. 30. Tests that 'runaway' or take too long, can be automatically failed There are two options for implementing timeout
  31. 31. Timeout parameter on @Test Annotation (applies to test method) @Test(timeout=1000) public void testWithTimeout() { ... } #1
  32. 32. 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
  33. 33. OK for JUnit Let’s see now...
  34. 34. Mockito is a Java framework allowing the creation of test double objects (mock objects) in automated unit tests
  35. 35. Test Double is a generic term for any case where you replace a production object for testing purposes
  36. 36. 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
  37. 37. <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
  38. 38. 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();
  39. 39. Once created, mock will remember all interactions Then you can selectively verify whatever interaction you are interested in
  40. 40. 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!
  41. 41. 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));
  42. 42. 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
  43. 43. //stubbing using built-in anyInt() argument matcher when(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 matcher verify(mockedList).get(anyInt()); Here are some argument matchers
  44. 44. 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
  45. 45. Verifying exact number of invocations / at least x / never //exact number of invocations verification verify(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");
  46. 46. Verification in order Single mock whose methods must be invoked in a particular order List singleMock = mock(List.class); //using a single mock singleMock.add("was added first"); singleMock.add("was added second"); //create an inOrder verifier for a single mock InOrder 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");
  47. 47. Verification in order Multiple mocks that must be used in a particular order List firstMock = mock(List.class); List secondMock = mock(List.class); //using mocks firstMock.add("was called first"); secondMock.add("was called second"); //create inOrder object passing any mocks that need to be verified in order InOrder inOrder = inOrder(firstMock, secondMock); //following will make sure that firstMock was called before secondMock inOrder.verify(firstMock).add("was called first"); inOrder.verify(secondMock).add("was called second");
  48. 48. Sometimes we need to stub with different return value/exception for the same method call, we need to stub consecutive calls (iterator- style stubbing)
  49. 49. 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");
  50. 50. 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)
  51. 51. 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* methods spy.add("one"); spy.add("two"); //prints "one" - the first element of a list System.out.println(spy.get(0)); //size() method was stubbed - 100 is printed System.out.println(spy.size()); //optionally, you can verify verify(spy).add("one"); verify(spy).add("two");
  52. 52. 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
  53. 53. Capturing arguments for further assertions with ArgumentCaptor //create the ArgumentCaptor for class Person ArgumentCaptor<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());
  54. 54. Sources http://junit.org/ http://en.wikipedia.org/wiki/JUnit http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html https://code.google.com/p/mockito/ http://en.wikipedia.org/wiki/Mockito http://www.martinfowler.com/bliki/TestDouble.html
  55. 55. Thanks

×