środa, 6 listopada 2013

Mocking and verifying collabolators in Spock and Mockito

Recently I started writing tests in Groovy for my apps. I found groovy a nice language for testing, thanks to its syntax. I also like the idea of BDD, and that's how I found Spock - a great BDD testing library.
Spock is a nice framework for testing with BDD style. It embraces the given/when/then pattern, and with groovy syntax writing test becomes a real fun. You can find more about spock on their website http://code.google.com/p/spock/

My first challenge was to rewrite tests that use mocks. Previously all mocks were done using Mockito library. If you dont know Mockito, try it out :)
I'm not going to spend too much time on this part either, as it's well documented.
Just a quick example, to create and verify that mock was used with Mockito, normally you would do something like that


        @Test
 public void testMockInteraction() {
                Collabolator collabolator = Mockito.mock(Collabolator.class);
                Mockito.when(collabolator.foo()).thenReturn(1);
                MyTestObject subject = new MyTestObject();
                subject.setCollabolator(collabolator);
                subject.doSomethingWithCollabolator();
                Mockito.verify(collabolator).foo()
 }

So, if you require some result from your collabolator mock, you need to do the Mockito.when() first, and after subject method called, you verify that collabolator was actually called by Mockito.verify(). Simple. How would you transfer this to Spock? Does not seem to be tricky at all, isn't it?
        
 def "test mock interaction"() {
                given:
                MyTestObject subject = new MyTestObject()
                Collabolator collabolator = Mock()
                subject.setCollabolator(collabolator);
                collabolator.foo() >> 1
                when:
                subject.doSomethingWithCollabolator()
                then:
                1 * collabolator.foo()
 }
So, looking at this it seems legit, and very similar to Mockito based code. We are given some prerequisites with test object, a mock, and mock operation definition. In when part we call the subject test method, and in then we verify that collabolator was called. But this won't work! At least not as you expected. Assuming you dont do anything with the result for the foo method, the test may pass. But let's assume that doSomethingWithCollabolator() looks like this
        
 public long doSomethingWithCollabolator() {
               return 13 + collabolator.foo()
 }
Now, you will get an exception because at this point, collabolator will return null, and 13 + null = Exception :) So why you get null from collabolator? There is a definition to return 1 on call to foo() in given clause... It does not work like that. There is some magic behind Spock, which does code tranformations. In Spock, you combine the Mockito.when() and Mockito.verify() in then clause, so test should look like this
        
 def "test mock interaction"() {
                given:
                MyTestObject subject = new MyTestObject()
                Collabolator collabolator = Mock()
                subject.setCollabolator(collabolator);
                when:
                subject.doSomethingWithCollabolator()
                then:
                1 * collabolator.foo() >> 1
 }
Strange at the begining, but handy when you catch it. Saves you from lot of typing comparing to Mockito.

Brak komentarzy:

Prześlij komentarz