Wednesday 2 May 2012

Mockito Example


A Nice Glass Of Mockito Please

The question asked when using TDD or even writing tests is why would someone
want to use mocks? Well suppose you have the following class:
  1. package blog.code;

  2.  public class Hello {

  3.    public String hello() {
  4.      return null;
  5.    }

  6.    public void
         greeting(String greeting){
  7.    }
  8.  }
Not very special. One is a function called greeting which gives a greeting
and the other is a function which returns a hello string. As you can see they don't.

But what if I didn't know about that? And now I want to use them in a new class.

Well I would need to mock them and make them spit back the correct answer.

Let's use TDD. Test first and using mockito, if you are using maven then grab
the mockito-all dependency, it is easily compatible with Junit. There are
plenty of other API's such as easymock, jmock and mockit but I like this one
as it is simple.
  1. package blog.code;

  2. import static org.junit.Assert.*;
  3. import static
       org.mockito.Mockito.*;
  4. import org.junit.*;

  5.   public class HelloWorldTest {
  6.     HelloWorld helloWorld;
  7.     Hello mockHello;

  8.     @Before
  9.     public void before(){
  10.       helloWorld =
            new HelloWorld();
  11.       mockHello =
            mock(Hello.class);
  12.       when(mockHello.hello()).
            thenReturn("Hello");
  13.       helloWorld.
            setHello(mockHello);
  14.     }

  15.     @Test
  16.     public void
          testHelloWorldReturns
             HelloAndGreets(){
  17.       String helloWorldString =
            helloWorld.helloWorld();
  18.       assertEquals(
            helloWorldString,
              "Hello");
  19.       verify(mockHello).
            greeting(anyString());
  20.     }
  21.  }
Let's just talk about what has happened in this simple test.
First of all I have to import mockito (line 4).
Then in the Before You have to set up a mock.
In this case I have called it mockHello, after the class Hello. Look at line 14.
It was that simple to set it up "mockHello = mock(Hello.class)" This acts
almost as if you had called a new version of hello. Only when I ask it to do
something I can make it return a dummy version, which means Hello doesn't
have to do the things I want it to. You can then proceed to stub what you like
(almost, you can mock static things, new things, private things and final things) .
So whenever this any test sees mockHello.hello it will return the string "Hello"
(line 16). DON'T FORGET TO SET HELLO WITH THE MOCK.
That is pretty important, if you don't set it with the mock then it won't work.

That's the before, now on the the real test. couldn't be easier, like normal with
Junit all you have to do is assertEquals on the string you expect and on then function.
However what mockito will let you do, which you can't do with Junit without
changing voids to booleans. You can "verify" (line 23). you
"verify(mock).method" you can see here I also have a function called "anyString()".
This comes with mockito, anyString(), anyObject(), anyInt(). It will be the most
appropriate null value or be anyString/Object/Int. If you use anyObject you would
have to cast the object, e.g. "(User) anyObject()"

So now that this compiles but fails (well it will compile if you have the method shell) .
All we have to do is make the tests pass.
  1. package blog.code;

  2.   public class HelloWorld {

  3.     private Hello hello;

  4.     public String helloWorld(){
  5.       String helloString =
             hello.hello();
  6.       hello.greeting("NYtn H3r3")
  7.       return helloString;
  8.     }

  9.     public setHello(Hello hello){
  10.       this.hello = hello;
  11.     }
  12.  } 
Very box standard. I would put a getter in and make helloString an external variable in.
Note on line 9 I have put in anyString and the test will pass. I could actually make this
test pass even faster. If I were to just return "Hello" and call the method.
What you could do is verify that "hello" is called. You can also check if it is called in
the correct order. You can do loads of things to not only get 100% code coverage but
to also check that your functions are doing what you thought they were, as opposed to
just getting 100% code coverage (assuming you don't have static stuff...)

I was thinking I would make the next blog about powermock however I am still
trying to compose a good example. With this, power mock and Junit you can actually
get 100% code coverage. Well that is almost true, you should learn how to use reflection.

I am thinking that I will have to make the next blog on TDD. Because it is so awesome.

Enjoy mocking, Solid.Pope

No comments:

Post a Comment