Some Thoughts On Testing Search
Search is actually a very interesting case when considering what to test and where. Having just touched this again, from the vantage point of a machine that is crazy fast, we opted for just going straight to some Spring tests that actually look for the real things. The advantage is that you will find out:
- if the query itself is parseable
- if the search mechanism can find any results
- if it found the results you wanted
Typically I like to think of testing as occurring in layers where the first thing to do is unit test the component, and in most cases, mocking things works well here, and there is no need for Spring, so the tests run very fast. In this case, though, what is the component in search? There isn‘t one really. I mean there might be an input form for gathering what the user wants, but that‘s going to be immediately translated into some query syntax and that‘s what we really need to test.
Due to the nightmarish nonsense that attends any attempt to test actual data, in the last round of wanting to test search, the decision was made to avoid testing the actual queries: just write a bunch of unit tests that showed that the query was conforming given the range of possible inputs (e.g., we support searching for things that are in ranges, in lists of possible values, etc., those all have to subscribe to some syntax so that the expression will be parseable, and since we don‘t anticipate having to concern ourselves with the possiblity that JPA will, for instance, suddenly decide not to honor its own syntax, we can kind of pin our own conformance to the specified requirements). This gets you pretty far, surprisingly, but then the actual conformance to the domain model becomes the next question. The simplest way to test this is to actually have the persistence engine parse the query. This is where we cross the Rubicon, no the River Styx.
Why, I keep asking myself, is it such bloody hell to put a database into a state, run a few tests, then restore the prior state? Seriously, if there was a strong counter argument to the facility that we have all sought in using ORM, this would be tops on my list. If this were an object database, we‘d just create a bunch of objects and stuff them in, then rollback or loop the objects and nuke them. I thought I‘d go check the latest spring doc to see what they were saying about transactions not allowing you to easily seed the db before testing. Quite predictably, there‘s just a dismissive gesture ‘unit tests shouldn‘t need data in the db, use a mock.‘ I did find a guy talking about using dbUnit with Spring 2.5. After looking at what looked like a serious Jeremiad, the first comment was to check out a project called Unitils, which actually does look pretty interesting, if seriously ambitious. They did their own mocking, and have support for JPA, and Spring, but have not been able to figure out yet what they do about putting the db into a known state.
The cleanest solution would be a Decorator. The guy who did his own thing I think does something smart: add an annotation to the test that includes the name of a dataset. What I like about that is it is a useful part of the documentation as well, and it keeps all loading/unloading code out of the tests themselves (or their ancestors). Maybe the decorator could be implemented as an aspect. But even with this decoration, the problem is how do we get the seeding scripts. It‘s a hassle making them in dbUnit. This is why the impedance relief coming back just to see if you are getting what you want is especially biting.