Mockarro changes name to Komarro, Komarro&Mockito

As Mockarro was not the prettiest name it has been changed to Komarro. I also cut out the Injection Point class from the SPI so that API stays as minimal as possible. According to the old saying: it’s much easier to add features to an API when they are demanded, than to remove them when it turns out they should not be there. During the last review I also realized that a possibility o defining a custom injection strategy has to be more flexible than it was.

I also created another example of ‘Komarro with Mockito’ usage.

Currently Komarro offers a possibility of defining indirect inputs to a tested method. Sometimes however, it is necessary to verify the indirect output parameters or to verify that an interaction with a collaborator took place.
As Komarro is built upon Mockito they play together quite smoothly.

Let’s consider a local Pizza delivery service. In the example below you can see both the elements of Komarro and Mockito APIs. The interaction verification will be done on the methods of the OrderRepository. That is why it is annotated by the Mockito @Mock annotation. And then initialized using the MockitoAnnotations.initMocks(this) method.
Also it is important to notice that the mocks created by Mockito can be passed to Komarro’s instanceForTesting initialization method. Here, the MockitoMockDescriptionCreator.annotatedMocks convenience method is used to automatically detect the mocks marked with the @Mock annotation.

	@Mock
	private OrderRepository orderRepository;

	private OrderService orderService;

	@Before
	public void init() {
		initMocks(this);

		orderService = instanceForTesting(OrderService.class,
				annotatedMocks(this));
	}

Then we are set and ready to write the actual test method:

	@Test
	public void testPlaceOrderSavesOrder() {
		// given
		given(Pizza.class).isRequested().thenReturn(new Pizza("Margharita"));
		given(Order.class).isRequested().thenReturn(newOrderWithId(17L));

		// when
		long orderId = orderService.placeOrder("margharita", new Address(
				"Embarcadero Rd 123", "Isla Vista", "93117"));

		// then
		verify(orderRepository).save(any(Order.class));
		assertThat(orderId).isEqualTo(17L);
	}

Note that the method uses the Komarro’s idiom to define the behavior of the collaborators and Mockito’s verify method to verify the interaction has taken place.
Komarro can be complemented with Mockito’s functionality every time it is necessary. All the verifications have to be done by Mockito, as Komarro does not provide any way to do this yet. But also, if it is happens that Komarro style definition does not provide a good definition of the indirect inputs, Mockito should be used.

The method under test could look like this:

	@Inject
	private OrderRepository orderRepository;

	@Inject
	private PizzaService pizzaService;

	public long placeOrder(String pizzaName, Address address) {
		Pizza pizza = pizzaService.getByName();

		if (pizza != null) {
			Order order = new Order();
			order.setAddress(address);
			order.setPizza(pizza);

			Order newOrder = orderRepository.save(order);

			return newOrder.getId();
		} else {
			throw new IllegalArgumentException("The pizza " + pizzaName
					+ " does not exist in the menu card");
		}
	}

The source code of the examples posted here (and some more tests) can be found at github: https://github.com/marekdec/komarro-example-pizza-shop. The important phases of the development have been tagged.

Advertisements

, , ,

  1. #1 by James Kennard (@webamoeba) on June 19, 2012 - 2:45 pm

    I don’t think this example makes sense. In particular the use of verify, this goes against the idea of asking and telling (http://monkeyisland.pl/2008/04/26/asking-and-telling/).

    Something that highlights this is the fact that you could call orderRepository#save(Order) with an erroneous Order and the test would still pass. I’m convinced the ‘any’ matcher is an invitation to write bad unit tests.

  2. #2 by marekdec on June 19, 2012 - 7:38 pm

    Hi James, good point, it was probably an unfortunate choice as the verify part is not the important one here – it was just to show that you can fall back to mockito when testing with komarro and using some non-komarro functionality (regardless what you want to do).

    Anyhow, Komarro is about the //given part of the test I should probably make it clearer here and of course make the examples better.

    Thanks a lot!

  3. #3 by James Kennard (@webamoeba) on June 24, 2012 - 10:42 am

    Komarro is interesting, although I don’t feel that I agree with premise on which it was created. Anyway I might have to have a go using it before I can really make an informed judgement. Although I do like the given().isRequested() syntax šŸ˜‰

    • #4 by marekdec on June 25, 2012 - 11:32 am

      The basic idea behind Komarro is to avoid coupling a ‘mockist test’ to the underlying implementation. In other words to avoid any calls to the collaborators’ methods (for example orderRepository#save(Order) – in the example it wass given to prove something else).

      So the initial idea was to demonstrate that it is possible to create tests with no references to collaborators implementation – even in the stubbing part of the fixture setup phase. (Sort of a response to this quite old Fowler’s article: http://martinfowler.com/articles/mocksArentStubs.html#CouplingTestsToImplementations).

      Anyways, I do encourage you to try it out šŸ™‚

      • #5 by James Kennard (@webamoeba) on June 29, 2012 - 9:49 am

        Interesting article, hadn’t seen that one before. I can see how Komarro constitutes a response to that. I think they key aspect that I was missing is the idea of allowing “expectations to be looser in areas where it doesn’t matter”, that is to say, I was looking at Kommaro as a complete solution for mocking all interactions, when in reality it is to be used in scenarios where we don’t care about the how it calls something just about the fact that it gets something.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: