Vishwanath Krishnamurthi's blog

A blog on Java EE, clean code, open source and TDD

Posts Tagged ‘Mockito

A few things to avoid while writing unit tests

with 2 comments

Long back I wrote a post on some good practices to follow while writing unit tests.  I thought I’d add one on mistakes/practices to avoid while writing unit tests.

1) Reading a configuration file:

If for writing a unit test, you access a file, then strictly speaking, it is not a unit test.

For example,

class CarTest
{
Engine engine;
// your test for engine object
}

If you created the object under test by doing,

Engine engine = new Engine();

that’s neat. Whereas if DI was used to create the ‘engine’ object, then it wouldn’t have been a unit test. (DI involves reading an external file/ scanning for annotations )

Likewise, if for test data, you retrieved the data from a file, then its not really a unit test.

the main drawback being ?

Reading files takes time. A unit test has to be really fast. Something that’s executed very often.

2) Mocking the wrong objects:

Mocking frameworks are great.  You could easily mock a ‘dao’ or a ‘service’ call and write a unit-test quickly. Mocking a ‘value-object’ like the one above is needless.

public void  AccountBalanceTest
{
@Mock AccountInfo accountInfo;
@Test
public void  debitShouldDecuctTheGivenAmount()
{
when(accountInfo.getCurrentBalance()).thenReturn(500);
Account account = new Account(accountInfo);
account.debit(100);
}
}

It turns out to be messy when a lot of such stub values are defined.

‘Value-Objects’ being easily constructible with a ‘new’ should rather be used like this:

@Test
public void  debitShouldDecuctTheGivenAmount()
{
AccountInfo accountInfo = new AccountInfo();
accountInfo.setCurrentBalance(500);
Account account = new Account(accountInfo);
account.debit(100);
}
}

This reads a lot better, doesn’t it? And when there are a lot of test data to be prepared, there’s of course the very useful builder pattern http://nat.truemesh.com/archives/000714.html

3) Ignoring the feedback

A great thing about writing tests is that you get “feedback” about your code.

For example,  if you started writing a test like this,

@Test
public void testValidateAddressShouldCheckForMandatoryPostCode()
{
Customer customer = new Customer();
Address address = new Address();
address.setPostCode("123456");
customer.setAddress(address);
Validator validator = new Validator();
validator.validateAddress(customer);
}

you should be seeing a “warning” here. You’re spending some effort constructing the object required for test,

and this “warning” should hint you that, the validateAddress() method should be refactored to take an address parameter and not a customer parameter.

It is easy to set up the object like above and get the test passing – but that’s not the point. The idea should be to take the feedback and refactor.

@Test
public void testValidateAddressShouldCheckForMandatoryPostCode()
{
Address address = new Address();
address.setPostCode("123456");
Validator validator = new Validator();
validator.validateAddress(address); // refactored method.
}

Yes, the above one was a simplified example, but hope the idea is clear.

Similarly, when a piece of code is hard to test, it is possible to overcome the pain by using some advanced mocking frameworks and finishing up the test. But “being hard to test” might be a feedback telling  you to take efforts to refactor the code and make it testable/loosely-coupled.

Here’s a great post http://martinfowler.com/articles/modernMockingTools.html that explains it.

So to put it again, “the feedback should not be ignored”

 

Good TDD resources

http://misko.hevery.com/
http://www.growing-object-oriented-software.com/
http://vimeo.com/10569751

 

Advertisements

Written by Vishwanath Krishnamurthi

April 9, 2012 at 11:49 pm

Posted in Design

Tagged with , ,

Using Mockito to unit test Spring Webflow

with 6 comments

The flows in Spring Webflow act as powerful controllers. And it is very crucial in a webapp to have the controllers tested.

Unit testing Spring Webflow becomes all the way easier, when a mocking framework is used. And I find Mockito to be pretty good in that arena.

Without much talk, here goes some code:

Step1:
To extend AbstractXmlFlowExecutionTests.

Let’s locate the flow-under-test as such

@Override
 protected FlowDefinitionResource getResource(
 FlowDefinitionResourceFactory resourceFactory) {
 FlowDefinitionResource resource = resourceFactory.createResource("foo-flow.xml");
 Assert.notNull(resource);
 return resource;
 }

Step2:

Mock away the beans used in flow


BazService mockedBazService;

@Override
 protected void registerMockFlowBeans(ConfigurableBeanFactory flowBeanFactory){
 mockedBazService=mock(BazService.class);
flowBeanFactory.registerSingleton("bazService",mockedBazService);
 flowBeanFactory.registerSingleton("barService", mock(BarService.class));
 flowBeanFactory.registerSingleton("MyExceptionHandler", mock(MyExceptionHandler.class));
 }
}

Note that I’m holding the reference for BazBean so I can do some stubbing using Mockito later..
Step3:
Then lets code up a test.

 MockExternalContext context = new MockExternalContext();
 @Test
 public void testFlowShouldEnterStartState()
 {
  this.startFlow(context);
  assertCurrentStateEquals("myFirstState");

 }

How about triggering an event, and checking a transition ?

@Test
 public void testStateWhenFooBarProcessingEventTriggered()
 {

   this.startFlow(context);
   context.setEventId("startProcessingFooBar");
   resumeFlow(context);
   assertCurrentStateEquals("fooBarProcessor");
 }

Some stubbing..

 @Test
 public void testProcessingDetails()
 {
    this.startFlow(context);
    when(mockedBazService
     .isDetailsAvailable(anyString())
     ).thenReturn(true);
    context.setEventId("processDetails");
    resumeFlow(context);
    assertCurrentStateEquals("processDetails");

 }

Enough to get started with testing webflows, I guess. I’ll update more later 🙂

Update:

Some more observations on SWF unit testing.

Written by Vishwanath Krishnamurthi

July 12, 2011 at 10:59 am