Unit Tests as documentation

27 October 2007

One of the advantages of doing test driven development & unit testing is having the unit tests as documentation of the code. When you read this in the unit testing / TDD books, it is hard to imagine how this would be of use in practice.

As one of my favorite bloggers, Jeremy Miller, already writes, the NHibernate source is a really good example of using the tests as documentation. I think this is especially the case when developing frameworks or libraries. Because the code will always be used by developers, the best way for a developer to see how the code should be used is by looking at the unit tests as an example.

I experienced this myself a couple of days ago with the same code that Jeremy mentions. I also used the NHibernate EnumStringType to use an enum type that is represented in the database as a string column. This works great, but when I wanted to use the enum type in a HQL query, it didn’t work the way I had expected:

 

IQuery q = s.CreateQuery("from Order as order where order.State =:orderState"); q.SetEnum("orderState", OrderState.Open); IList results = q.List();
The code above gave me a vague oracle exception. So i needed to figure out how to pass the parameter to the HQL query. I fired up the NHIbernate source to open the unit test for the EnumStringType:

I then opened the test, which gave me the right code:

 

[Test] public void ReadFromQuery() { ISession s = OpenSession();
        IQuery q </span><span style="color:#000000;">=</span><span style="color:#000000;"> s.CreateQuery(</span><span style="color:#000000;">"</span><span style="color:#000000;">from EnumStringClass as esc where esc.EnumValue=:enumValue</span><span style="color:#000000;">"</span><span style="color:#000000;">);
        q.SetParameter(</span><span style="color:#000000;">"</span><span style="color:#000000;">enumValue</span><span style="color:#000000;">"</span><span style="color:#000000;">, SampleEnum.On, </span><span style="color:#0000FF;">new</span><span style="color:#000000;"> SampleEnumType());
        q.SetEnum(</span><span style="color:#000000;">"</span><span style="color:#000000;">enumValue</span><span style="color:#000000;">"</span><span style="color:#000000;">, SampleEnum.On);
        IList results </span><span style="color:#000000;">=</span><span style="color:#000000;"> q.List();

        Assert.AreEqual(</span><span style="color:#000000;">1</span><span style="color:#000000;">, results.Count, </span><span style="color:#000000;">"</span><span style="color:#000000;">only 1 was 'On'</span><span style="color:#000000;">"</span><span style="color:#000000;">);

        q.SetParameter(</span><span style="color:#000000;">"</span><span style="color:#000000;">enumValue</span><span style="color:#000000;">"</span><span style="color:#000000;">, SampleEnum.Off, </span><span style="color:#0000FF;">new</span><span style="color:#000000;"> SampleEnumType());
        results </span><span style="color:#000000;">=</span><span style="color:#000000;"> q.List();

        Assert.AreEqual(</span><span style="color:#000000;">0</span><span style="color:#000000;">, results.Count, </span><span style="color:#000000;">"</span><span style="color:#000000;">should not be any in the 'Off' status</span><span style="color:#000000;">"</span><span style="color:#000000;">);

        s.Close();

        </span><span style="color:#008000;">//</span><span style="color:#008000;"> it will also be possible to query based on a string value
        </span><span style="color:#008000;">//</span><span style="color:#008000;"> since that is what is in the db</span><span style="color:#008000;">

s = OpenSession();

        q </span><span style="color:#000000;">=</span><span style="color:#000000;"> s.CreateQuery(</span><span style="color:#000000;">"</span><span style="color:#000000;">from EnumStringClass as esc where esc.EnumValue=:stringValue</span><span style="color:#000000;">"</span><span style="color:#000000;">);
        q.SetString(</span><span style="color:#000000;">"</span><span style="color:#000000;">stringValue</span><span style="color:#000000;">"</span><span style="color:#000000;">, </span><span style="color:#000000;">"</span><span style="color:#000000;">On</span><span style="color:#000000;">"</span><span style="color:#000000;">);
        results </span><span style="color:#000000;">=</span><span style="color:#000000;"> q.List();

        Assert.AreEqual(</span><span style="color:#000000;">1</span><span style="color:#000000;">, results.Count, </span><span style="color:#000000;">"</span><span style="color:#000000;">only 1 was 'On' string</span><span style="color:#000000;">"</span><span style="color:#000000;">);

        q.SetString(</span><span style="color:#000000;">"</span><span style="color:#000000;">stringValue</span><span style="color:#000000;">"</span><span style="color:#000000;">, </span><span style="color:#000000;">"</span><span style="color:#000000;">Off</span><span style="color:#000000;">"</span><span style="color:#000000;">);
        results </span><span style="color:#000000;">=</span><span style="color:#000000;"> q.List();

        Assert.AreEqual(</span><span style="color:#000000;">0</span><span style="color:#000000;">, results.Count, </span><span style="color:#000000;">"</span><span style="color:#000000;">should not be any in the 'Off' string</span><span style="color:#000000;">"</span><span style="color:#000000;">);

        s.Close();
    }</span></div></pre>
As Jeremy also mentions, the NHibernate documentation isn't as complete as we would have hoped, the EnumStringType isn't documented for example. But as the example above illustrates, these unit tests can be really helpful as technical documentation, especially when it concerns frameworks and libraries.