Showing posts with label test driven. Show all posts
Showing posts with label test driven. Show all posts

Thursday, September 3, 2009

Nifty little Java trick...

In Java, there are many times when you have to deal with collections.  The code that is required in order to build a collection can be pretty cumbersome and usually follows the following pattern:

List strList = new ArrayList;
strList.add("1");
strList.add("2");
strList.add("3");

This code above can easily be changed to one line of code as such:
List strList = Arrays.asList("1", "2", "3");

I have found this little trick especially useful when writing unit tests.

If you plan on using this test in production level code, then you should be aware that creating a list in this fashion, does not allow for editing the list later. Instead, you should wrap the newly formed list in a constructor like so:
List strList = new ArrayList(Arrays.asList("1", "2", "3"));

Enjoy...

Monday, August 11, 2008

EasyMock Tip

EasyMock is a light weight Mock library used for mocking interfaces in Unit Tests. Here is a little tip on what I believe to be an undocumented best practice.

Let's say you have a Unit Test that is testing an object called CustomerController. CustomerController has a dependency on Interface CustomerDao Typically, you may see in the unit test, code that looks similar to the following:

protected void setUp() throws Exception {
    controller = new CustomerController();
    custDao = createMock(CustomerDao.class);
    controller.setCustDao(custDao);
}

public void testFindCustomers() throws Exception {
    expect(custDao.getCustomers()).andReturn(new ArrayList());
    replay(custDao);
    controller.findCustomers();
    verify(custDao);
}

As you will notice, I am specifying one mock custDao, and the system under test is the controller. This is pretty standard and straightforward use of EasyMock. Now let's see what happens when we have to add an additional dependency on the controller:

protected void setUp() throws Exception {
    controller = new CustomerController();
    custDao = createMock(CustomerDao.class);
    invoiceController = createMock(InvoiceController.class);
    controller.setCustDao(custDao);
    controller.setInvoiceController(invoiceController);
}

public void testFindCustomers() throws Exception {
    expect(custDao.getCustomers()).andReturn(new ArrayList());
    replay(custDao);
    controller.findCustomers();
    verify(custDao);
}

public void testApplyCustomerPayment() throws Exception {
    Customer customer = new Customer();
    BigDecimal paymentAmt = new BigDecimal(100);
    invoiceController.applyPayment(customer, paymentAmt);
    replay(invoiceController);
    controller.applyPayment(customer, paymentAmt);
    verify(invoiceController);
}

This also seems to be a very valid test. I would argue though that it is not complete. You are verifying that the appropriate methods are called on the objects / interfaces that you set expectations for. However, if a method is called on the custDao in the controller.applyPayment or a method is called on the invoiceController during the controller.findCustomers, without an expectation / verification the test will still pass. This may not be the desired behavior and therefore I would argue that the test is incomplete.

On my team, someone determined that a way to handle these types of situations is to create a private method on the test called replayAll and verifyAll. This included the maintaining of an array list of all of the mocks that is used within the test. While this is a valid solution, I wanted to see what other EasyMock users were doing. Here is what I found:

protected void setUp() throws Exception {
    controller = new CustomerController();
    mockControl = createControl();
    custDao = mockControl.createMock(CustomerDao.class);
    invoiceController= mockControl.createMock(InvoiceController.class);
    controller.setCustDao(custDao);
    controller.setInvoiceController(invoiceController);
}

public void testFindCustomers() throws Exception {
    expect(custDao.getCustomers()).andReturn(new ArrayList());
    mockControl.replay();
    controller.findCustomers();
    mockControl.verify();
}

public void testApplyCustomerPayment() throws Exception {
    Customer customer = new Customer();
    BigDecimal paymentAmt = new BigDecimal(100);
    invoiceController.applyPayment(customer, paymentAmt);
    mockControl.replay();
    controller.applyPayment(customer, paymentAmt);
    mockControl.verify();
}

The subtle difference to look at between these two scenarios is that the latest one uses what is known as a IMocksControl object. This IMocksControl object keeps track of what mocks were created on it so that all you would need to do in order to make sure that you are replaying and verifying all of the mocks is to call the replay and verify methods on the IMocksControl object. This ensures that all of the expectations, whether explicit or implied, are met. Thanks Tammo Freese for your help in finding this great golden nugget within the EasyMock framework.

Wednesday, April 18, 2007

TDD Koolaid :- Sip don't Chug

I have been getting into a lot of discussion lately regarding Test Driven Development. For those of you that do not know me, I am a TDD practioner (some may call me a fanatic). However, I was not always that way...

My TDD journey began a couple of years ago when someone handed me the book Extreme Programming Installed. I was part of team given the task to evaluate different Methodologies for Software Development. Fate led me to study Extreme Programming, but I will leave that for a different post. In my view, the best way to learn something is to put it into practice. Test Driven Development seemed like as good a candidate as any to start learning Extreme Programming, so I did.

Starting to practice Test Driven Development was not easy. For so long, I had operated in the mode of "Coding Blindly". The cycle of doing J2EE development was lengthy and insane: write code, compile, build distribution, deploy to application server, pray that it works!!! To change that mindset, as ridiculous as it was, was a challenge. Instead, I started to force myself to write tests against the business logic layer of my application. (Only recently have I started writing tests against the Data Access Layer, due to lack of methodologies of doing so). By writing my tests first, no longer was I operating blindly. Through the use of expectations, I had a goal in front of me that I was trying to reach and I was rewarded by the "almighty green bar" when I reached it.

I actually found myself working less. By writing the tests first, and building tests against objects and methods that were not even created yet, I allowed the IDE (Integrated Development Environment) to do all of the heavy lifting for me. With a click of a button, I was able to create classes and methods that allowed my tests to compile. With some creativity, I was able to control behavior of the dependencies, and test many scenarios that were impossible if not difficult to do while I was "Coding Blindly".

I have to admit, TDD was not easy to get used to. It required a lot of time, patience and research. I would like to challenge all of you who are reading this post to start applying some of the test driven practices. If you are having a hard time "chugging the TDD Koolaid" sip it instead. Take small steps and watch how more productive you become, how clean your code looks, how much more secure you will feel in the code that you write, and not to mention how much fun it will become.