Ayende @ Rahien

It's a girl

When Query Objects are a first level concern

I mentioned that I recently had a shift in my think about having services that return query objects. Now I have more interesting problems. How do I test such a thing? To be more accurate, how do you test such a thing in an accurate & maintainable way? To say that queries can be complicated is an understatement. You can try to deconstruct the query, but is this a really good idea? Something as simple a inner vs. left join can have interesting implications.

I guess that I am asking whatever this approach still allows for a Unit Test.

Right now I am testing that against an in memory database, so it mostly involved setting up the data, calling the service that returns the query, execute that and verify the results.

Any thoughts?

Comments

Chris Bilson
06/24/2007 12:45 PM by
Chris Bilson

I guess that you should be testing requirements not implementation. It's not important what kind of join is used or the language of the query, but that it returns all the gold customers that haven't ordered more than $50 in a single month in the past 18 months, for example. I would set up test data in the in memory database and verify that the query returned the results required.

The interesting thing is that the query itself, rather than being a piece of data to check as would usually be the case, is a new piece of code to test. The same concept as lambda functions.

So my opinion: test code, not data, or even code that looks like data (the query object.) You have to execute it, not just decompile it.

Ralf Kretzschmar
06/24/2007 04:52 PM by
Ralf Kretzschmar

I agree with Chris: You'll have to execute the query, to make sure that it works. Than the main work within the test would be to set up the data. One thing that facilitates this is the usage of the Object Mother pattern.

That we still have to use a real database to do that might disappear when we will use some form of Specification in the Fowler/Evans sense, that can be reliably translated into the native tongue of the underlying db. I think LINQ is a step in that direction: If you have a LINQ query, you can run it against an in-memory collection or you let it translate into SQL or HQL/Hibernate Criteria or whatever to run it against the real thing.

One thing to remember is the fact that a query - in the way they are today - not only specifies what would match but also what to bring along eagerly and what to fetch lazily. From a testing perspective it would be nice if these two concerns could be separated, then the matching part could be tested against an in-memory object graph which would be a true unit test and not an integration test that uses a real database (even if that db is in-memory). But for the fetching part my guess is that I would still need to hit the real implementation of the db.

What has always bothered me is the duplication that can come with querying. Lets take an example: My business entity "Order" has a property "IsVeryInteresting". The value of this property is not stored but is determined by an arbitrarily complex calculation of some sort. Using the property is a piece of cake when I already have an instance of an order. But if I want to use the same property in a query I can only opt for either storing the result of the calculation (which would fail if my understanding of a "very interesting order" will change some day) or duplicate the logic for calculating the value within the query (which is against DRY). I would like to have someone to ask for a description of how to find out if a order is "very interesting" and than use that description against an order instance or in a query.

Comments have been closed on this topic.