Lab 3

Lab 3 SVV

Mock Unit Testing

Step 1

Download archive Attach:MockUnit3.zip, then go to Eclipse, close existing projects and then, from the File menu: choose option Import... > Existing Projects into workspace > Select archive file > Browse > choose the downloaded MockUnit3.zip file > Finish

Go on and write tests for the following cases:

 0 tags -> ZeroTag.html 
1 tag -> OneTag.html
2 tags -> TwoTags.html
0 tags -> Empty.html

Step 2 - Mocking

In class TagsParser add the method below, in order to use the dependency injection pattern.

  1 public void setProvider(HttpStringProvider p) {
  2         this.provider = p;
  3 }

In the test class TestTagsCounter add the test method below (please notice how it creates an anonymous inner class derived from HttpStringProvider)

   1 @Test
   2 public void testCounterWithAnonimous() {
   3         TagsParser counter = new TagsParser("http://www.loose.upt.ro/vvswiki") ;
   4         counter.setProvider(new HttpStringProvider(){
   5                 @Override
   6                 public String getStringForAddress(String urlAddress) {
   7                         return "";
   8                 }
   9         });
  10         assertEquals(0, counter.getTagsCount());
  11 }

We can add the inner class in the test class TestTagsCounter, as below:

   1 private static class HttpStringProviderOneTag extends HttpStringProvider {
   2         @Override
   3         public String getStringForAddress(String urlAddress) {
   4                 return "<html></html>";
   5         }
   6 }

We can also build a single generic mock class, to use for all required tests:

   1 private static class GenericHttpProviderMock extends HttpStringProvider {
   2         @Override
   3         public String getStringForAddress(String u) {
   4                 return u;
   5         }
   6 }

See a usage example for the generic mock in the test method below

   1 @Test
   2 public void testCounterWithAnonimous() {
   3         TagsParser counter = new TagsParser("<b><b></b>") ;
   4         counter.setProvider(new GenericHttpProviderMock());
   5         assertEquals(2, counter.getTagsCount());
   6 }

Step 3 - Mockito

The code you have seen above introduces a type of testing that uses mock objects, specifically created by us in order to tackle a certain issue. Mock testing helps us test the code of each class in true isolation, without the added complexity of interacting with real third party API libraries. Since this situation is rather frequent in many projects, there are now many libraries that enable their users to easily create and use mock objects when writing tests. Some of the most popular such libraries are EasyMock and its follow-up, Mockito.

In the following we will highlight some basic features offered by the Mockito library, and then we will revisit the example at Step 2 using Mockito. Let us first download the last version of Mockito, and then let us create a new Eclipse project under the name of MockitoTest. After creating the project we add the external library from the downloaded archive as following: select project > right click on the project > select Build Path > Add External Archives >> choose the Mockito library (mockito-all-X.X.X.jar, where X.X.X is the version number).

We then create a unit test class under the name PlaygroundTest, as below:

   1 import static org.mockito.Mockito.*;
   2 import java.util.List;
   3 import org.junit.Test;
   4 
   5 public class PlaygroundTest {
   6 
   7         @Test
   8         public void invocation() {
   9                 //mock creation
  10                 List<String> mockedList = mock(List.class);
  11 
  12                 //using mock object
  13                 mockedList.add("one");
  14                 mockedList.clear();
  15 
  16                 //verification
  17                 verify(mockedList).add("one");
  18                 verify(mockedList).clear();
  19         }
  20 }

In this first test method we are creating a mock for class java.util.List (usually we will not be mocking container/collection types, but fill them up with mock objects instead - best practices; however, in this case, we have chosen to mock List for simplicity, as it is a very well known interface and mostly everyone is aware of its features). Do notice how easily the mock object has been created, all we had to do is invoke the static method mock(). Notice that we can call the List interface methods add and clear on the mock object, and then we can check whether these methods have been called via the static method verify offered by Mockito. In the case of method add, we see that we can also verify whether it has been invoked with a specific parameter, in this case with string "one".

So, Mockito offers us the static method verify, which allows us to make sure that certain methods have been invoked on our pseudo-objects. We can also check how many times they have been invoked (default is 1), and for what parameters.

We will now write another test method, as below:

   1 @Test(expected = RuntimeException.class)
   2 public void stubbing() {
   3         // You can mock concrete classes, not only interfaces
   4         @SuppressWarnings("unchecked")
   5         LinkedList<String> mockedList = mock(LinkedList.class);
   6 
   7         // stubbing
   8         when(mockedList.get(0)).thenReturn("first");
   9         when(mockedList.get(1)).thenThrow(new RuntimeException());
  10 
  11         Assert.assertEquals("first", mockedList.get(0));
  12 
  13         // "null" because get(999) was not stubbed
  14         Assert.assertEquals(null, mockedList.get(999));
  15 
  16         // following throws runtime exception
  17         System.out.println(mockedList.get(1));
  18 
  19         // Although it is possible to verify a stubbed invocation, usually it's
  20         // just redundant
  21         // If your code cares what get(0) returns then something else breaks
  22         // (often before even verify() gets executed).
  23         // If your code doesn't care what get(0) returns then it should not be
  24         // stubbed.
  25         verify(mockedList).get(0);
  26 }

Here we are preprogramming our mock object to respond in a certain, needed way. Using the static method when offered by Mockito, we have preprogrammed our mock so that if method get is called on it with parameter 0 it will return the string "first", and if it is invoked with parameter 1 it will throw an exception of type RuntimeException.

The static method when from Mockito is widely used to specify what results we wish to receive when calling a certain method with certain parameters on the pseudo-objects we have created.

   1 @Test
   2 public void matchers() {
   3         @SuppressWarnings("unchecked")
   4         LinkedList<String> mockedList = mock(LinkedList.class);
   5         // stubbing using built-in anyInt() argument matcher
   6         when(mockedList.get(anyInt())).thenReturn("element");
   7 
   8         Assert.assertEquals("element", mockedList.get(0));
   9         Assert.assertEquals("element", mockedList.get(999));
  10 
  11         // you can also verify using an argument matcher
  12         verify(mockedList, times(2)).get(anyInt());
  13 }

In the above test method we can see a way of getting a certain preprogrammed result when calling method get() no matter the actual value of its parameter, as long as it has the primitive int type. This is done by using an argument matcher. There are several such matchers available in the Mockito library, so please go to the official Mockito documentation in order to read more about those matchers and how you can use them. Keep in mind that you can also use them when verifying if a certain method call has been done on a mock, not just for preprogramming mock objects.

   1 @Test
   2 @SuppressWarnings("unchecked")
   3 public void invocationTimes() {         
   4         LinkedList<String> mockedList = mock(LinkedList.class);
   5         mockedList.add("once");
   6         mockedList.add("once again");
   7 
   8         mockedList.add("twice");
   9         mockedList.add("twice");
  10 
  11         mockedList.add("three times");
  12         mockedList.add("three times");
  13         mockedList.add("three times");
  14 
  15         // following two verifications work exactly the same - times(1) is used
  16         // by default
  17         verify(mockedList).add("once");
  18         verify(mockedList, times(1)).add("once");
  19 
  20         // exact number of invocations verification
  21         verify(mockedList, times(2)).add("twice");
  22         verify(mockedList, times(3)).add("three times");
  23 
  24         // verification using never(). never() is an alias to times(0)
  25         verify(mockedList, never()).add("never happened");
  26 
  27         // verification using atLeast()/atMost()
  28         verify(mockedList, atLeastOnce()).add("three times");
  29         verify(mockedList, atLeast(2)).add("three times");
  30         verify(mockedList, atMost(5)).add("three times");
  31 
  32         // create an inOrder verifier for a single mock
  33         InOrder inOrder = inOrder(mockedList);
  34 
  35         // following will make sure that add is first called with
  36         // "was added first, then with "was added second"
  37         inOrder.verify(mockedList).add("once");
  38         inOrder.verify(mockedList).add("once again");
  39 
  40         // verify that method was never called on a mock
  41         verify(mockedList, never()).add("two");
  42 
  43         List<String> firstMock = mock(List.class);
  44         List<String> secondMock = mock(List.class);
  45 
  46         // verify that other mocks were not interacted
  47         verifyZeroInteractions(firstMock, secondMock);
  48 }

In the test method above we have done several different verifications: that our methods have been called for a certain number of times, that they have never been called, or that there were no interactions at all in our code with certain mock objects. These are all very useful use cases for the Mockito library, which can widely simplify the way we write tests. There are many other things to discover on your own, so please take a look at the official Mockito documentation.

Let us now take another look at our example from Step 2, and let us rewrite it using Mockito for mock testing.

   1 @Test
   2 public void testCounterWithAnonimous() {
   3         HttpStringProvider mockStringProvide = mock(HttpStringProvider.class);
   4         when(mockStringProvide.getStringForAdress(anyString())).thenReturn("<b><b></b></b>");
   5         
   6         TagsParser counter = new TagsParser("http_address");
   7         counter.setProvider(mockStringProvide);
   8         
   9         assertEquals(2, counter.getTagsCount());
  10         verify(mockStringProvide).getStringForAdress("http_address");
  11 }

So, we have created a mock object of type HttpStringProvider, and we have specified that we wish to return a string containing two tags ("<b><b></b></b>") no matter the actual value of the string parameter used to call method getStringForAdress. In order to initialize the instance of class TagsParser we have used some default test string ("http_address"), and then we have verified that the same string has been then passed as parameter when calling method getStringForAdress. Please notice how Mockito not only offers us more testing possibilities than the naive mock testing from Step 2, but also help us get rid of some boilerplate mock testing code, while both simplifying our tests and making them easier to read / more comprehensible.