Friday, 10 July 2009

EasyMock - Reason to update to the latest version

I have recently started working on a new project that consisted of three dependant Java projects.

These three projects were using two different versions of EasyMock so first off I decided to bring them into line. The projects are all Java5 but one project had EasyMock 2.4 and the other two had EasyMock 1.3

Following on from Andrew Beacock's article on using easy mock's class extensions I decided to give that a go.

Strangely after upgrading some of the tests were failing. Why ?

Well it looks to me like a bug in the old version of EasyMock 1.3,
so the easy answer is upgrade. The bug appears to be that you can not call MockControl.expectAndDefaultReturn() more than once.

Here is the test using the old code, and below that a test class using 2.4.

EasyMock 1.3 version:
package uk.co.utilisoft.entrecaweb.web.validators;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;

import org.easymock.MockControl;

public class TryOldEasyMock extends TestCase{

public void testSingleCall(){
List<String> list = new ArrayList<String>();
list.add("hello");
MockControl control = MockControl.createControl(TestMock1.class);
TestMock1 mock = (TestMock1)control.getMock();

ClassUnderTest1 classUnderTest = new ClassUnderTest1();
classUnderTest.setService(mock);

control.expectAndDefaultReturn(mock.getLength("hello"), 5);
control.replay();
assertEquals(5, classUnderTest.getLength(list));
control.verify();
}


public void testTwoCalls(){
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("bye");

MockControl control = MockControl.createControl(TestMock1.class);
TestMock1 mock = (TestMock1)control.getMock();

ClassUnderTest1 classUnderTest = new ClassUnderTest1();
classUnderTest.setService(mock);

control.expectAndDefaultReturn(mock.getLength("hello"), 5);
control.expectAndDefaultReturn(mock.getLength("bye"), 95);
control.replay();


assertEquals("this is the wrong value & should fail.", 190, classUnderTest.getLength(list));
assertEquals("this is the correct value & should pass.", 100, classUnderTest.getLength(list));
control.verify();
}
}

class ClassUnderTest1{
private TestMock1 service;

public void setService(TestMock1 service) {
this.service = service;
}

public int getLength(List<String> someText)
{
int total = 0;
for (String value : someText) {
total += service.getLength(value);
}
return total;
}

}

interface TestMock1
{
public int getLength(String someText);
}


EasyMock 2.4 version, using the class extensions jar:
package uk.co.utilisoft.entrecaweb.web.validators;

import java.util.ArrayList;
import java.util.List;

import junit.framework.TestCase;
import static org.easymock.classextension.EasyMock.*;

public class TryEasyMockTest extends TestCase {

public void testSingleCall()
{
List<String> list = new ArrayList<String>();
list.add("hello");

TestMock mock = createMock(TestMock.class);

expect(mock.getLength("hello")).andReturn(5);

ClassUnderTest classUnderTest = new ClassUnderTest();
classUnderTest.setService(mock);
replay(mock);

assertEquals(5, classUnderTest.getLength(list));
verify(mock);
}

public void testTwoCalls()
{
List<String> list = new ArrayList<String>();
list.add("hello");
list.add("bye");

TestMock mock = createMock(TestMock.class);

expect(mock.getLength("hello")).andReturn(5);
expect(mock.getLength("bye")).andReturn(95);

ClassUnderTest classUnderTest = new ClassUnderTest();
classUnderTest.setService(mock);
replay(mock);

assertEquals(100, classUnderTest.getLength(list));
verify(mock);
}
}

class ClassUnderTest{
private TestMock service;

public void setService(TestMock service) {
this.service = service;
}

public int getLength(List<String> someText)
{
int total = 0;
for (String value : someText) {
total += service.getLength(value);
}
return total;
}

}

class TestMock
{
public int getLength(String someText){
return someText.length();
}
}

Wednesday, 8 July 2009

Testing Times - Freezing Times

I have found many tests that want to set a time in a class and then test that that object has the correct time set.

Often these tests will pass when run locally as unit tests but either fail as integration tests which tend to be slower or fail when run on a heavily loaded build server.

I came across the solution on Mark Needham's Blog making use of a joda-time.

There appears to be may other usefull classes such as LocalDate, a class that just holds the date, yep the bit that says 25/12/2009 with no time representation, ie just a date !!!

Monday, 15 June 2009

Eclipse - java.lang.RuntimeException unable to get class information for @throws tag for SomeException

Working in Eclipse, I had a previously working project that I had closed.

After reopening it I found it was littered with apparent errors,
that were not there before.

Somehow checkstyle had got confused. Simply turning checkstyle off and back on again removed all the errors.

Tuesday, 19 May 2009

DbUnit and nullable columns

We use DbUnit for our database integration tests and this works very well allowing us to populate the database with test data specific for the test at hand.

I have had a problem for the last few hours that has driven me to distraction. I was populating a table with a row and the tests using this data were all OK.

I then added an extra row that also wanted to populate an extra nullable column. The test failed because the test thought this column was null. I stopped the test in the debugger and yes the code was correct, the column was null. What could be wrong ?

My DbUnit XML looked like this:
<dataset>
<MY_TABLE
ID="1"
MANDATORY_COL="This column must have data"
/>

<MY_TABLE
ID="2"
MANDATORY_COL="This column must have data"
NULLABLE_COL="This column is nullable"
/>
</dataset>


The problem appears to be that DbUnit builds its list of columns from the first occurrance of each table. Any optional columns listed in subsequent entries are simply ignored.

There are two solutions. Either reverse the order of the two items in the XML file, or set the column to null in the rows where the nullable column is not required.

Friday, 15 May 2009

TDD Testing of Dependancy Injection in Spring

Spring relies very heavily on dependancy injection and when writing integration tests the first thing that must work before you even try to connect to things like your database is that all your beans must be correctly injected.

So before I get all excited and start writing tests that read or write to the database I write a very simple test to check that everything has been injected correctly.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
}
}

Strictly speaking this test testInjection is not needed at this stage because the test will fail if the injection of this primary bean fails.

Ok so I need to create the bean.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
</bean>

The test will now pass.

The test now gets more useful as I now extend the test to see if FooService has its beans injected successfully.

public class FooServiceIntegrationTest extends BaseIntegrationTester{
private FooService fooService;

public void setFooService(BulkUploadService aFooService){
fooService = aFooService;
}

public void testInjection() throws Exception{
assertNotNull("FooService not injected", fooService);
assertNotNull("FooService not injected", fooService.getBarDao());
}
}

Now this will not compile at first as fooService.getBarDao() does not exist.
I add this to the interface and implement the method and re-run the test,

The test fails as we have not set the property on the bean so lets do that.

<bean id="fooService" name="fooService" class="uk.co.foo.FooServiceImpl">
<property name="barDao" ref="barDao" />
</bean>

Assuming barDao has also been configured then the test will now pass.

Possibly others do this, I do not know but I have found this little test invaluable as a precursor to grander integration tests later on.

BTW BaseIntegration tester does little more than extend AbstractTransactionalDataSourceSpringContextTests and implement the method getConfigLocations()

Thursday, 14 May 2009

Eclipse Hot Keys and the language bar on Windows

I like to use Eclipse Hot Keys and two of my favourites are Ctrl+Shift+R (open a resource) and the very similar Ctrl+Shift+T.

Sometimes when in eclipse I would do something and suddenly find the double quote and '@' keys (among others) had swopped.

I sussed out that somehow I was changing my keyboard settings from English UK to English US. I left it at that now I knew I could fix it.

Today I sussed out why and how to stop it happening again.

The hot keys to change the language is Ctrl+Shift and I must have been missing off the R or T.

So assuming you do not want to change the keyboard from one to the other at all or not too often you have two options:
a) disable the hot keys
b) remove the language you do not want.

To do this go to: Contol Panel->Regional & Language options->Languages->Details.

If you want to disable the hot keys select Key Settings->'Change Key Sequence'.
If you want to remove one of the languages, select one and then select 'remove'

Thursday, 9 April 2009

Spring User Group in the North West

Last night was the inaugrial North West Spring User Group.

There were two speakers, Jan Machacek of Cake Solutions and a joint author of Pro Spring 2.5 and Rob Harrop from SpringSource and also joint author with Jan on the original 'Pro Spring' book

Jan gave an excellent worked example of a small web application using Spring 3.0 and Rob also ran a worked example on REST development in Spring. Rob's talk was particularly interesting and brave in that he was willing to show the REST development at the cutting edge and show and admit to its weaknesses with it being only at milestone release.

There will be future meetings and you can follow them at the Linkedin User group