Be Persistent

If you want to change yourself, you might be able to do it within 5 minutes. But if you want to change an organization change needs time. Even when you are the CEO, change doesn’t happen because you announced it on a big meeting. But

If you push towards change,

If you don’t give up,

If you try over and over again,

If you try different approaches,

If you talk to everyone who lets you talk,

someday change will happen no matter what your official title is.

Be persistent if the cause is worth it.

Posted in: The Rest by Jens Schauder No Comments

Properties of a Good Unit Tests

Question: what are the properties which make a test a good unit test? If you have a good answer, check out my answer and add to it in the comments. If you don’t here is mine.

Long Descriptive Name: For example returnsNullWhenCalledOnEmptyList is a nice name for a test

Simple Clean Structure: A test performs necessary setup, executes the method to be tested and performs its assertions. Not more not less

Fast: one thousand tests should run in less than a minute. This allows an extensive test suite to run often during development. If your tests are slower, you might be doing integration tests.

Test a Single Feature or behavior: This is sometimes phrased as ‘one assertion’, which I consider misleading. If you need multiple assertion in order to assert one behavior thats OK, although you might consider a new assert method for that.

Reliable: For the same code base a test should produce the same result every time. A test that fails every 10th time will fail for a real bug and you won’t know it.

Stable: The test only fails, when the code under test doesn’t behave as expected, not because anything else changed.

Easy to Understand: Just as normal code, the intention of a test should be easy to understand. Names help with this. Extracting setup code in a properly named method helps as well.

Should Not Use Production Classes, Except The Class Under Test: This helps with the ‘Stable’ and the ‘Fast’ property. It’s ok to use simple classes like String or Integer.

Don’t Try to Squeeze All Tests for a Class in a Single Test Class: For many classes you will have more then one test class. The different test classes will probably differ in the setup needed for the contained tests.

Independent: No Test should depend on any other Test or on the order of execution.

Posted in: Softwaredevelopment by Jens Schauder 3 Comments

An Analysis of NonUniqueObjectException and LazyInitializationException in Hibernate

I consider Hibernate a great and useful tool. But it has some mean Exceptions lurking in the darker corners. Today I’d like to explore the ones from the title in a little more detail, including different approaches on how to avoid them.

Let’s start with the well known LazyInitializationException. When you search for this one in the Internet you end up with scenarios like this one:

You load A, close the session you  used and try to access a property of A which gets loaded lazily resulting in a LazyInitializationException. That one is well described, including strategies to avoid it, which basically consist of not closing the session to early.

But there are more hideous scenarios. Assume the classes Mom, Dad and Kid are mapped as one would expect, with references from Mom and Dad to Kid. Now consider the following piece of code:

  1. Session session = openSession();
  2. session.beginTransaction();
  3.  
  4. Mom mom = (Mom) session.load(Mom.class, momId);
  5. Kid momsKid = mom.getKid();
  6.  
  7. // dad comes by
  8. Dad dad = (Dad) session.load(Dad.class, dadId);
  9. Kid dadsKid = dad.getKid();
  10.  
  11. // and leaves
  12. session.evict(dad);
  13.  
  14. // alas he has taken kido with him
  15. momsKid.getName();

Depending on your exact Mapping you might get a LazyInitializationException in the last line, although the session is still open. The problem here is that when dad got evicted the kid got evicted as well. And since Mom has a reference to the exact same object, that object isn’t attached to any session anymore. In order to see this effect you’ll have to use mappings like this:

@ManyToOne(fetch = LAZY, cascade = CascadeType.ALL)
  1.     @Cascade(org.hibernate.annotations.CascadeType.ALL)
  2.     private Kid kid;

The NonUniqueObjectException gets caused by what could be considered the reverse process. Examine the following piece of code:

  1.         // Dad left for another woman, I mean Session
  2.         Dad dad = loadDad();
  3.  
  4.         Session session = openSession();
  5.         session.beginTransaction();
  6.  
  7.         Mom mom = (Mom) session.load(Mom.class, momId);
  8.         System.out.println(mom.getKid().getName());
  9.  
  10.         // Now dad wants to move back in
  11.         session.saveOrUpdate(dad);

The first method call loads a Dad object including Kid from a different session. Then from the ‘main’ session Mom gets loaded including kid. When we attach the Dad object to the session it tries to attach its version of the Kid as well, which collides with the Kid already present in the session.

So how can we avoid these kind of problem? I see several options:

  • Don’t use Cascade. Of course this means much more effort on your side in many cases, since you have to carefully track what you need to attach or evict from a session.
  • Don’t use evict and don’t reattach existing instances to sessions. I guess this should work in many cases. But I have seen cases where this approach would have caused a large overhead, because reloading complex object graphs.
  • Carefully design your cascading boundaries. A look at the Aggregate Root from DDD might help here. An Aggregate Root is a single class which works as a gate keeper (did anybody say facade) to a cluster of classes related to the Aggregate Root. When all the Hibernate related actions go against that Aggregate Root, and cascade from there to the content and only the content of the Aggregate Root you should be safe. All entities outside an Aggregate Root have to use the Aggregate Root or Repositories to gain access. This needs some bookkeeping. But when you do it properly it might actually improve the over all design of your code. Please note that all this is a thought experiment on my side, and I can’t promise that it actually works as intended, but I think it should.

If you want the complete source code for the example, you can download this source.zip file.