ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Agile Database Refactoring with Hibernate
Pages: 1, 2, 3

Test, Test, Test

Extensive testing is one of the most important activities during the creation of a DMA solution. Only thorough testing can ensure a correctly functioning view-based (logical) data model. All aspects of the new data model must be explored in tests. And, of course, it is imperative to test both working cases and failing cases.



A great aid in automating testing is DBUnit. Although we won't go into great detail on how DBUnit works (a great OnJava article by Andrew Glover already does that) a couple of important pointers should be noted:

  • Data diversity: Make sure your test data clearly reflects all sorts of different data scenarios, including foreign key relationships and null values.
  • Dataset size: Although it is important to maintain a large enough data set to support all of your tests, keep in mind that DBUnit empties and reloads your data during every test method. Large data sets may lead to slow testing.

As far as the tests themselves, look at them as a way to exercise your DAOs and value objects. Here are some of the kinds of tests we recommend. For a closer look at the implementation, look at the sample code included with this article.

  • Find All: Make sure the DAO returns the expected number of rows.
  • Find one: Look up a record using the virtual primary key and make sure the correct record is returned with all the expected (column) values in place.
  • Insert: Insert a record and verify it has been inserted.
  • Insert multiple records: Make sure inserting is working for more than one skill at a time.
  • Insert duplicates: Attempt to violate the virtual primary key constraint.
  • Delete: Delete a record and verify that it has really been deleted.
  • Delete multiples: Do so only if your DAO design supports doing this.
  • Update: Update and make sure the update has been persisted to the DB.
  • Violate constraints: Make sure all possible virtual constraint conditions are tested.
  • Optimistic locking: There are several ways to generate optimistic locking exceptions. All of these should be attempted in order to verify the correct functioning of the optimistic locking exception mechanism. Four different kinds of optimistic locking conditions should be tested:
    • Delete a record when a record has already been deleted.
    • Delete a record when it has been updated since the last fetch (only possible if you are maintaining a version column).
    • Update a record that has been deleted.
    • Update a record that has been updated since the last fetch (only possible if you are maintaining a version column).

Once you have completed all of these tests, you can be confident that your new data model is fairly bomb-proof.

Peaceful Coexistence

Now that you have upgraded your application to use a sane data model, keep in mind that other applications will be accessing the same data using slightly different points of contact. This shouldn't worry you, it's just something to keep in mind. Figure 3 demonstrates how your new and improved application lives peacefully alongside the existing legacy applications.

figure
Figure 3. A legacy application and the DMA solution coexisting peacefully and manipulating the same data set albeit through different models

Now What? Migration to a Permanent Data Model

So you've implemented this fancy solution to fix your data model. As the months go by, developers update their applications and begin to use this new view-based data model. But the underlying denormalization (or whatever faulty design exists) is still there, and you want to get rid of it. But how? It's actually simpler than you might think. Here is the step-by-step guide:

  1. Develop tables: These will look much like your views, but will have real foreign keys and indexes. Make sure to maintain the same column names as the views themselves.
  2. Load tables: You will load the tables with data from your already existing views. Select from view into table. It's really that simple.
  3. Modify your mappings: Change your Hibernate mappings to reflect the table names instead of the views and, if you used stored procedures, get rid of the <sql-insert>, <sql-update> and <sql-delete> elements (since now you won't need them).
  4. Test, test, test: Your original tests should work with absolutely no modification. Run them over and over again to prove that.

Voila! If you've done things right, not a single line of Java code needs to be modified, and your applications will behave exactly the same. This is where the true beauty of this kind of solution is evident. By abstracting the data model through Hibernate and database procedures, you can achieve an impressive change with little effort. Of course, this doesn't mean that you shouldn't retest everything thoroughly--the good news is that your tests are still totally valid as well (if you are using XML data sets, make sure to replace the view name with the table name).

Conclusion

Using some of the latest and greatest Hibernate technologies, Java testing methodologies, and smart use of your databases resources, we have shown you that iterative change is possible. What is magical about solving data model problems this way is that the solution is mutually inclusive. This means that while you have solved the problem for yourself (in your application), other applications accessing the same data can continue to operate fine until they wise up and jump on your corrected bandwagon. It's a really friendly approach to data model migration.

As a final note, we would like to remind you to keep the following in mind when implementing your solution:

  • Zero impact: DMA solutions must not affect current applications or processes. This means that while records are modified in the new (virtual) data model, the existing set of data (in the faulty data model) must reflect the change.
  • Maintain functionality: While a new data model may eliminate the importance of certain data columns, it is important to simultaneously maintain the old behavior. Calculated fields are a perfect example of this. If a legacy application calculates a field before insertion, but the new data model doesn't even include the field, the DMA solution must respect the old behavior and calculate (and insert) the field.
  • Testing for complete confidence: DMA solutions that are created must be thoroughly tested in order to provide confidence that the new schema is as solid as a direct database schema is. The DMA pattern may not be a straightforward mapping of tables and columns, and is therefore vulnerable to bugs. The challenge then, is in testing the solution and making sure it adheres to complete ACID principles.

Resources

Gilad Buzi has been involved in data driven application development for over ten years. He is currently a Principal Software Engineer with The Code Works Inc.

Kelley Glenn has worked in the software development industry for more than 10 years, with experience in telephony billing and enterprise application integration.

Jonathan Novich is co-founder and partner at The Code Works, Inc. with more than 10 years of experience in software consulting and development.


Return to ONJava.com.