Thursday, March 5, 2009

Spring TestContext Framework

It has been an exciting, and at the same time, frustrating time for the past few days.
For better or for worse, I decided to take a dive into Spring MVC and Spring Webflow, trying and playing around with it.

I walked away knowing more about Spring TestContext Framework instead.

Before I begin, I have to conclude that Spring MVC is really very neat. Webflows was interesting, and came with its own testing framework, which kinda irritates me... (they should all stick to Spring TestContext Framework instead). However, the inability to test the resulting view properly (without firing up Selenium) was a sore point for me..

So anyway, back to Spring TestContext Framework. It really is extensible.
Almost.

I could create custom TestExecutionListener, hook it up with the test class, and have it run before/after every test method!

So my first experiment was to do a MockTestExecutionListener. What it basically do is to create mocks of fields marked with @Mock (much like MockitoAnnotations). Pretty simple and easy. Then I hook it up to my test class.

The fastest way was to use @TestExcutionListeners, but I would have to declare DependencyInjectionTestExecutionListener as well, so that it would still remember to perform Spring Injection. Whatever classes declared in @TestExecutionListeners would override the default TestExecutionListener that Spring offers in SpringJunit4ClassRunner.

So instead, I extended SpringJUnit4ClassRunner, and added my TestExecutionListener in TestContextManager#getDefaultTestExecutionListenerClasses.

And then I got abit more adventurous.

I tried to reuse my mocks, and at the same time, verify that there were no more interactions in the afterTestMethod. So I kept track of my mocks in the given TestContext, and verify them.

The painful part was reusing the mocks. There is just no clean way to remove all interactions from mocks created from Mockito cleanly. Short of duplicating code from Mockito internals, cleaning delegates, blah blah blah. I'm trying to forget the ugly part of it.

So now, we have auto-mocking for our Spring Test!

And the next step. Wouldn't it be nice if some of my mocks are autowired to my Spring objects?

There is just no way it could be done nicely, especially if mocks are recreated for every test method execution.

A custom context loader can be provided, which can customize the loading of an application context.

Singletons are created and cached. And the application context are cached as well. So if two classes are using the same set of test configurations, the application context are cached across two class executions.

So it probably is out of the question.

And then I started playing with DbUnit. It is an excellent candidate for TestExecutionListener. It can auto locate a dataset xml file, initialize it for each test method invocation, and verify that the current state of the database match an expected dataset.

Only grip I had was in order to provide a DataSource to my TestExecutionListener, I had to locate it via the current test's application context.

Spring TestContext Framework is a very interesting framework, but it would be better if many methods are not made final, and better ability to declare custom classes instead of the in-built TestContext, TestContextManager, etc.

blog comments powered by Disqus