Today, I've finally released version 1.0 of DbMaintain. DbMaintain is a new open-source project that enables the automatic roll-out of updates to a relational database. It brings database scripts into version control just like regular source code and can be used to transparently deploy databases from development to production. DbMaintain automates the part of the deployment which is most difficult to automate, opening the door for fully automated deployments in all stages of development.
Although it's a new project, the functionality already exists for a number of years in the Unitils project. Originally it started as a simple system for automatically managing the database that is used for running tests against. The DbMaintainer has matured a lot the last 2 years and has grown to be a very powerful and complete solution, usable for a lot more than maintaining the unit test database alone. That's why I decided to split it off into a new project. At my current customer, we've been using a beta version of the system to automate the deployment of a number of applications, and it appears to work very well!
zaterdag 21 februari 2009
donderdag 7 februari 2008
Disable constraints on your test database
For testing persistence layer logic, DbUnit's simple system for defining test data in combination with Unitils integration features is the simplest and most efficient way. One of the most contested guidelines that we promote in this area is disabling the foreign key and not-null constraints in the test database. People tend to see it as a serious devaluation of tests, since code that's been successfully validated with unit tests, could appear not to work when testing end-to-end with a normal database.
The goal of database constraints is to guard database integrity. This is a good thing, since inconsistent data in production databases can cause a lot of problems. But unit tests are there for testing functionality, they've got little to do with data integrity. Persistence layer tests should in the first place show that queries return the correct records. This has nothing to do with constraints: If the query appears to return the correct data on a constraintless database, it will also do this on a database with the constraints enabled.
A database may of course have misplaced or missing constraints, but unit tests are not the right tool to discover these. Unit tests are not sufficient as proof of correctness of code anyway: You always need to do integration tests on a database with constraints enabled. In most cases, misplaced constraints will quickly be reveiled by integration and acceptance tests.
Disabling constraints saves a lot of time: You only have to define data for columns that is used in query logic: join columns and columns on which a condition is specified. You don't have to bother putting the records in the correct sequence, so that records to which is referred are inserted first. With constraints enabled, a lot of extra data must be defined. Referred records must be filled, records referred by these records must be filled, not-nullable columns in these referred records must be filled. Every time a not-nullable column is added, you need to adapt a lot of test data files. When there's time pressure, you'll even be tempted to make the extra column nullable, just to avoid this.
The constraints should be disabled automatically. If not, it takes extra time, it's often forgotten, it's annoying. Unitils' database maintainer offers a very efficient way of automatically maintaining test databases. Constraints are automatically disabled, sequences are put to a sufficiently high value and an XSD is generated to be used for validation and autocompletion in data set files.
The goal of database constraints is to guard database integrity. This is a good thing, since inconsistent data in production databases can cause a lot of problems. But unit tests are there for testing functionality, they've got little to do with data integrity. Persistence layer tests should in the first place show that queries return the correct records. This has nothing to do with constraints: If the query appears to return the correct data on a constraintless database, it will also do this on a database with the constraints enabled.
A database may of course have misplaced or missing constraints, but unit tests are not the right tool to discover these. Unit tests are not sufficient as proof of correctness of code anyway: You always need to do integration tests on a database with constraints enabled. In most cases, misplaced constraints will quickly be reveiled by integration and acceptance tests.
Disabling constraints saves a lot of time: You only have to define data for columns that is used in query logic: join columns and columns on which a condition is specified. You don't have to bother putting the records in the correct sequence, so that records to which is referred are inserted first. With constraints enabled, a lot of extra data must be defined. Referred records must be filled, records referred by these records must be filled, not-nullable columns in these referred records must be filled. Every time a not-nullable column is added, you need to adapt a lot of test data files. When there's time pressure, you'll even be tempted to make the extra column nullable, just to avoid this.
The constraints should be disabled automatically. If not, it takes extra time, it's often forgotten, it's annoying. Unitils' database maintainer offers a very efficient way of automatically maintaining test databases. Constraints are automatically disabled, sequences are put to a sufficiently high value and an XSD is generated to be used for validation and autocompletion in data set files.
zaterdag 5 januari 2008
Eclipse favorite static imports
Static imports are a great invention: Often used utility functions no longer need to be explicitly prefixed by their class name. This is especially useful for the assert* methods in unit tests. Older testing frameworks like JUnit 3.x needed to define all assert methods in the base superclass for convenience. Newer frameworks like TestNG and JUnit4 don't make you extend a superclass anymore and offer assert statements in a separate utility liberary, which is of course a good thing.
However, this also comes with a cost: while with JUnit3's TestCase superclass, all assert* statements were directly available, you now need to start typing static import statements in your tests first. This is annoying, especially if you use multiple external assert libraries.
Luckily, IDE's start offering some support. In Eclipse 3.3 for example, you can define your favorite static imports. Just go to window -> preferences -> java -> editor -> content assist -> favorites, and add the Assert libraries that you regularly use, such as junit.framework.Assert.* and org.unitils.reflectionassert.ReflectionAssert.*.
If you now start typing assert and press ctrl + space, the assert methods pop up just as if you already imported them. When you select a method, the static import gets automatically added to you imports list!
However, this also comes with a cost: while with JUnit3's TestCase superclass, all assert* statements were directly available, you now need to start typing static import statements in your tests first. This is annoying, especially if you use multiple external assert libraries.
Luckily, IDE's start offering some support. In Eclipse 3.3 for example, you can define your favorite static imports. Just go to window -> preferences -> java -> editor -> content assist -> favorites, and add the Assert libraries that you regularly use, such as junit.framework.Assert.* and org.unitils.reflectionassert.ReflectionAssert.*.
If you now start typing assert and press ctrl + space, the assert methods pop up just as if you already imported them. When you select a method, the static import gets automatically added to you imports list!
Abonneren op:
Berichten (Atom)