NHibernate Forge
The official new home for the NHibernate for .NET community

The best way to solve NHibernate bugs? Submit good unit test

There's no better way to explain some code-related issue than providing a test for them, and that is what any NH team member is going to ask you no matter how clearly you described it; that said.. why not being smart enough to provide it since the beginning?

For those who doesn't know what a unit test is, or why could possibly be useful, a unit test is nothing more than a method with some code in it to test if a feature works as expected or, in your case, to reproduce a bug. What makes them so useful is the ability to automatically execute them all; if you hypothetically had a set of test for every feature you coded into the software you're designing, after every change you could test if everything is still working or something got broken. If that triggered your attention, you can read further information on Unit Tests and Test Driven Development here and here, while here you can download and get some info on NUnit, which is the testing framework NHibernate team is currently using; obviously you can google around a bit for more info on this topic, as I'm going to focus on how testing applies to NHibernate bug fixing process.

Ok, back on topic then. If you dared to download NHibernate sources from SourceForge, or perhaps the trunk itself using a SVN client, you'd find a well established test project with some base classes you should use to implement the test. BTW, for the sake of simplicity, I created a C# project extracting only the few classes you need to build a test, so you don't need to use the actual NH sources anymore. You can download it here.

The project has the following structure, which is very similar to the one you'd find in the official sources:

image

I've mantained classes and namespaces naming in order to let your test compile in the actual NH test project without (hopefully) changing anything on it. Next steps will be

  • Building a small domain model along with its mappings
  • Setting up the test class
  • Create the test itself
  • Run the test to verify that it reproduces the bug
  • If it does, open a Jira issue and attach the test

Please note that all the code should be located in a NHSpecificTest folder's subfolder named like the Jira entry you submitted (for example, NH1234). So, once you've created the issue, you should do a little refactoring work to modify your test's folder and namespaces.

Domain Model and mappings

It would be hard to test an ORM without a domain model, so a simple one is mandatory, along with its mappings. My advice here is to keep things as simple as possible: your main aim should be trying to isolate the bug without introducing unnecessary complexity.

For example, if you find out that NHibernate isn't working fine retrieving a byte[] property when using a Sql Server 2005 RDBMS (it isn't true, NHibernate can deal quite well with such kind of data), you should create a domain entity not so different from the following:

   1: namespace NHibernate.Test.NHSpecificTest.NH1234
   2: {
   3:     public class DomainClass
   4:     {
   5:         private byte[] byteData;
   6:         private int id;
   7:  
   8:         public int Id
   9:         {
  10:             get { return id; }
  11:             set { id = value; }
  12:         }
  13:  
  14:         public byte[] ByteData
  15:         {
  16:             get { return byteData; }
  17:             set { byteData = value; }
  18:         }
  19:     }
  20: }

Mappings of such a simple domain model should be quite easy and small sized; the standard way to proceed is creating a single mapping file, named Mappings.hbm.xml, containing mapping definitions of all your domain model.

   1: <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernate.Test"
   2:                    namespace="NHibernate.Test.NHSpecificTest.NH1234" default-access="field.camelcase"
   3:                    default-lazy="false">
   4:   <class name="DomainClass">
   5:     <id name="Id">
   6:       <generator class="assigned" />
   7:     </id>
   8:     <property name="ByteData" />
   9:   </class>
  10: </hibernate-mapping>

As we're going to see shortly, test base class, in his default behavior, looks for such a file in test assembly's resources and automatically adds it to NHibernate configuration.

Setting up the test class

A test class is nothing more than a class decorated with the TestFixture attribute and which inherits (in our test environment) from BugTestCase base class. If you remember, we are going to test a fake bug about NHibernate incorrectly retrieving a byte[] property from the database. That means that first of all we're going to need a database with a suitable schema and then an entity already stored in it.

The default connection string points to a localhost server containing a test database called NHibernate; if your environment fits well with that, you have nothing to change in the app.config file. The test base class takes care of creating all the tables, keys and constraints that your test needs to play fine, taking into account what you wrote on the mapping file(s).

What about the entity we should already have into a table to test the retrieving process? The right way to inject custom code before the execution of a test is overriding the OnSetup method:

   1: protected override void OnSetUp()
   2: {
   3:     base.OnSetUp();
   4:     using (ISession session = this.OpenSession())
   5:     {
   6:         DomainClass entity = new DomainClass();
   7:         entity.Id = 1;
   8:         entity.ByteData = new byte[] {1, 2, 3};
   9:         session.Save(entity);
  10:         session.Flush();
  11:     }
  12: }

That code is invoked once per test, just before its execution; the infrastructure provides a OnTearDown virtual method as well, useful to wipe away your data from the tables and present a clean environment to the next test being executed:

   1: protected override void OnTearDown()
   2: {
   3:     base.OnTearDown();
   4:     using (ISession session = this.OpenSession())
   5:     {
   6:         string hql = "from System.Object";
   7:         session.Delete(hql);
   8:         session.Flush();
   9:     }
  10: }

The test class is almost setted up, we only need one last element: our imaginary bug happens only when dealing with a Sql Server 2005 database, things seem to be fine with other RDBMS. That means that the corresponding test only makes sense when that dialect has been selected, otherwise it should be ignored; another virtual method, called AppliesTo, serves for this purpose and can be overridden to specify a particular dialect for which the test makes sense:

   1: protected override bool AppliesTo(NHibernate.Dialect.Dialect dialect)
   2: {
   3:     return dialect as MsSql2005Dialect != null;
   4: }

Coding the test

The test method is were you'll describe how NHibernate should behave although it actually doesn't. It's a traditional C# method, that usually ends with one or more Asserts, by which you verify whether things went as you expected. Our "fake" bug was "In Sql Server 2005, NHibernate can't correctly load a byte array property of an entity"; a good test for that could be something like

   1: [Test]
   2: public void BytePropertyShouldBeRetrievedCorrectly()
   3: {
   4:     using (ISession session = this.OpenSession())
   5:     {
   6:         DomainClass entity = session.Get<DomainClass>(1);
   7:  
   8:         Assert.AreEqual(3, entity.ByteData.Length);
   9:         Assert.AreEqual(1, entity.ByteData[0]);
  10:         Assert.AreEqual(2, entity.ByteData[1]);
  11:         Assert.AreEqual(3, entity.ByteData[2]);
  12:     }
  13: }

Your test class may contain as many test methods as you need to better show the cases in which you experienced the issue. If it relies on NHibernate 2nd level cache, you can turn it on and off simply overriding the CacheConcurrencyStrategy propery in your test class:

   1: protected override string CacheConcurrencyStrategy
   2: {
   3:     get { return "nonstrict-read-write"; }
   4: }

Please remember that in the simple test project I provided, 2nd level cache is disabled by default. However, NHibernate official test project uses nonstrict-read-write caching strategy for every entity, because every "green" test should pass with caching enabled as well.

Conclusions

When NHibernate doesn't work as expected, the best way to describe the issue is providing a good unit test. NHibernate.LiteTest helps you writing tests that are so similar to the official ones to be directly integrable in the actual NHibernate trunk. So, if you think you've just discovered a bug,

  1. Go to NHibernate Jira and use its search engine to look for a similar bug (perhaps your problem has already been fixed and you only need to wait for a new release)
  2. If you don't find anything, write a unit test to reproduce it
  3. Execute NUnit and test it
  4. if NUnit bar is red (and NHibernate documentation doesn't state that it's a not supported case), go to the Jira, open a issue, rename your test folder and namespaces with the actual issue number (ex. NH1234) and upload it as an attachment.

Obviously, if you think you're good enough, no one will be offended if you submit a patch, too.


Posted oct 04 2008, 08:04 a.m. by Crad
Filed under:

Comments

Tuna Toksoz wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-04-2008 14:08

Good article, Crad!

I suggest executing the test cases against the trunk because it may already be fixed but not yet released.

If I am to summary what to do,

1. Download the trunk, use it always(even if one isn't going to create patch)

2. Search jira for similar issues, and if there is nothing similar and you still think that it is a bug to be fixed, create a jira issue.

3. Create NHxyzt folder(xyzt being the bug number).

4. Add your domain classes and then mappings(Mappings.hbm.xml)

5. Create the test code which illustrates the problem. Override OnSetUp and OnTearDown for your initial data and other initializations.

6. Run the test case see if it is failing.

7. If you know how to fix, then fix it in NHibernate project, if not, it still fine.

8. Create the patch against src folder using

     Right Click "src" folder and go to Tortoise SVN->Create Patch. Make sure it doesn't contain any dll's(A test case doesn't need compiled file, source is fine) and contain the files you have modified, don't forget to include .csproj files.

9. Add the patch to Jira.

Tuna Toksoz wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-04-2008 15:34

And I think we need to define coding standards.

Things like camelCase for fields, etc.

Fabio Maulo wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-04-2008 15:34

- The patch is better in a specific separate file.

About "Download the trunk" it is enough with "Download the last available version", for somebody "trunk" is an heavy world.

Another point is:

If you find a similar issue but it was closed, please, create a new one with your specific test if the old one was closed as fixed.

Cradle wrote Alcune info per chi usa NHibernate
on 10-04-2008 15:37
jnapier wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-06-2008 14:00

I think information contained in this article should be included in this post. This article describes exactly what should be done to get started creating a test for a jira issue and I dont believe this is referenced anywhere through out the wiki

www.hibernate.org/428.html

Dario Quintana wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-07-2008 10:53

Nobody is maintaining nhibernate.org domain. You should find here at NHForge for every NHibernate info.

Best regards

jnapier wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-10-2008 23:02

Dario,

My point was, that there is valuable information in this link, www.hibernate.org/428.html, that is not mentioned here and hopefully it can be pulled over into this post. For example there is information on how to configure nhibernate for your test environment without changing app.config.

Fabio Maulo wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 10-11-2008 2:55

@jnapier

Info on how configure NH are available here

www.nhforge.org/.../your-first-nhibernate-based-application.aspx

The ways to configure NH is outside the scope of this blog-post

Adrian wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 11-22-2008 5:11

I suggest moving this post over to the Wiki.  It covers an issue of central importance to NH and, obvious from comments above, many people are interested in improving upon it.  Moving it over would make it possible to incorporate these, and other, improvements into the original article.

Fabio Maulo wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 11-22-2008 10:19

You are right.

darius.damalakas@gmail.com wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 06-09-2009 4:29

Fabio, very good post.

And i agree that you expressed your opinion actively on NH-1818.  That kind of bug report is not good, i wastes lots of NH supporters time.

kanderson wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 08-06-2010 15:00

The links to download the sample test projects (www.nhforge.org/.../70.aspx) give Access Denied errors.

Tom Marien wrote re: The best way to solve NHibernate bugs? Submit good unit test
on 11-08-2010 8:06

Please update this post as it seems test project is no longer available and i have no clue how to get trunk building.

I'd like to submit a bug and a fix :)

video wrote video
on 09-08-2014 2:53

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Read More Listed here wrote Read More Listed here
on 09-27-2014 18:47

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Turbo FAST Hack Tool wrote Turbo FAST Hack Tool
on 10-02-2014 20:56

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Call of Mini Infinity Hack Tool wrote Call of Mini Infinity Hack Tool
on 10-14-2014 18:28

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

clash of clans astuce wrote clash of clans astuce
on 10-21-2014 18:05

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

online shopping in hk wrote online shopping in hk
on 10-22-2014 15:35

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

car accident victorville ca wrote car accident victorville ca
on 10-24-2014 13:44

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Sonic Jump Fever Hack Tool wrote Sonic Jump Fever Hack Tool
on 10-25-2014 10:08

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

More Clients wrote More Clients
on 10-31-2014 8:24

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Webhosting wrote Webhosting
on 11-12-2014 16:23

The best way to solve NHibernate bugs? Submit good unit test - NHibernate blog - NHibernate Forge

Powered by Community Server (Commercial Edition), by Telligent Systems