Liz Douglass

Archive for the ‘JUnit’ Category

Testing database naming conventions in Java

leave a comment »

I was recently reminded about some tests that we ran as part of the continuous integration build on my last project – tests that made sure that the database table, column and constraint names adhered to the client’s standards. The idea is quite simple and did on a number of occasions during development prove to be very useful. These tests certainly avoided any last-minute pre-release manual testing.

The tests were all contained in a single class and ran from a Buildr project (below). The tests use JUnit and Hamcrest along with Java SQL:

public class DatabaseNamingStandardsTest {

    private static Set tableNames;
    private static Connection connection;

    @BeforeClass
    public static void connectToOracle() throws SQLException, 
                                                ClassNotFoundException, 
                                                IOException {

        String configFileName = System.getProperty("config_file");

        Properties properties = new Properties();
        properties.load(new FileInputStream(configFileName));

        String url = properties.getProperty("database.url");
        String driver = properties.getProperty("database.driver");
        String username = properties.getProperty("database.username");
        String password = properties.getProperty("database.password");

        Class.forName(driver);

        connection = null;
        connection = DriverManager.getConnection(url, username, password);

        tableNames = listOfTableNames();
    }

    @AfterClass
    public static void tearDownConnections() throws SQLException {
        connection.close();
    }

    private static Set listOfTableNames() throws SQLException {
        Statement statement = connection.createStatement();
        ResultSet resultSet = statement.executeQuery(
                "SELECT table_name\n" +
                "FROM user_tables");
        Set result = new HashSet();
        while (resultSet.next()) {
            String tableName = resultSet.getString("TABLE_NAME");
            result.add(tableName);
        }
        return result;
    }

    @Test
    public void tableNamesShouldBeOfMaximum25CharactersInLength() {
        for (String tableName : tableNames) {
            assertThat(tableName.length(), lessThan(26));
        }
    }

    @Test
    public void ColumnNamesShouldBeOfMaximum30CharactersInLength() throws SQLException {
        Statement statement = connection.createStatement();
        for (String tableName : tableNames) {
            ResultSet resultSet = statement.executeQuery(
                    "SELECT * \n"
                    +"FROM user_tab_columns \n"
                    +"WHERE table_name='" + tableName + "'");
            while (resultSet.next()) {
                String columnName = resultSet.getString("Column_Name");
                assertThat(columnName.length(), lessThan(31));
            }
        }
    }
....
}

And here is the Buildr project definition…

define 'database-naming-standards' do
  test.with LIQUIBASE_JAR, JUNIT_JAR, HAMCREST_JAR, ORACLE_CLIENT_JAR
  test.using :properties => { :config_file => ("../../#{$oracle_properties_file}")}
  test.setup(
    ORACLE_DB_SCHEMA.rollback_all,
    ORACLE_DB_SCHEMA.update
  )
  package(:jar)
end
Advertisements

Written by lizdouglass

April 19, 2009 at 7:27 am

Posted in Building, Java, JUnit

Tagged with , ,

The same, but different

leave a comment »

Recently I’ve been using JUnit. In keeping with the most up to date libraries, we upgraded our project this week to JUnit 4.4 to JUnit 4.5 and that’s where we encountered a hiccup….

In our project, we are interested in doing specific things if a test has failed. For the purposes of demonstration, lets suppose that we want to output the test name to the console when a test fails (using a method annotated with @After). How do we know whether a test has failed or not? We can access this information by using a custom test runner that extends the JUnit4ClassRunner (in JUnit 4.4), like this one …

public class MyTestRunner
   extends JUnit4ClassRunner
{
   private static String
     failureMessage = null;

   public static String getFailureMessage() {
      return failureMessage;
   }

   public MyTestRunner(Class klass)
      throws InitializationError
   {
      super(klass);
   }

   public void run(final RunNotifier notifier) {
      failureMessage = "";
      notifier.addListener(new FailureListener());
      super.run(notifier);
   }

   private class FailureListener
      extends RunListener {

      public void testFailure
        (Failure failure) throws Exception {
           failureMessage = failure.getTestHeader();
        }
      }
}

Our runner (above) overrides the run method (only) so that we can add a FailureListener to the RunNotifier. As per the observer pattern, our notifier will call the testFailure method if the test fails, thereby setting the failureMessage. We can access the failure message from our @After method like this…

@RunWith(MyTestRunner.class)
public class MyClassTest
{
   @After
   public void printRunStatusMessage()
   {
      if (!MyTestRunner.getFailureMessage().equals(""))
         System.out.println(MyTestRunner.getFailureMessage());
      else
         System.out.println("Test did not fail");
   }

   @Test
   public void shouldAssertTruth() throws Exception
   {
      assertEquals(true, false);
   }
}

Note that our test class is annotated with @RunWith(MyTestRunner.class) – meaning that we are running the tests using our custom runner. If we go ahead and run the shouldAssertTruth test we get this line printing to the console “shouldAssertTruth(com.thoughtworks.blogdemo.test.MyClassTest)”. Ta da!

In the migration to JUnit 4.5, we discovered that JUnit4ClassRunner is now deprecated. It has been replaced with the new BlockJUnit4ClassRunner. According to the JUnit API documentation the BlockJunit4ClassRunner “should have exactly the same behavior as the old test class runner (JUnit4ClassRunner)”. By simply substituting the old runner class with the new one and re-executing the shouldAssertTruth test we get (drumroll) “Test did not fail” output to the console… hmm, that’s not expected….

In JUnit 4.4 there are calls to an addFailure method scattered throughout the code that executes the @Before, @Test and @After annotated methods for each test. This is what the addFailure method looks like:

protected void addFailure(Throwable e) {
   fNotifier.fireTestFailure
      (new Failure(fDescription, e));
}

This method lets us know immediately when a test has failed and is the reason why our custom runner worked so well. In JUnit 4.5 we now have the concept of Statements, and without going into detail about them, JUnit now has a RunAfters class. This class is used when we want to run a test and execute its associated @After methods. The class looks like this…

public class RunAfters extends Statement {
   private final Statement fNext;
   private final Object fTarget;
   private final List fAfters;

   public RunAfters(Statement next,
      List afters,
      Object target) {
         fNext= next;
         fAfters= afters;
         fTarget= target;
   }

   @Override
   public void evaluate() throws Throwable {
      List fErrors = new ArrayList();
      fErrors.clear();
      try {
         fNext.evaluate();
      } catch (Throwable e) {
      fErrors.add(e);
      } finally {
         for (FrameworkMethod each : fAfters)
            try {
               each.invokeExplosively(fTarget);
            }
            catch (Throwable e) {
               fErrors.add(e);
            }
         }
      if (fErrors.isEmpty())
         return;
      if (fErrors.size() == 1)
         throw fErrors.get(0);
      throw new MultipleFailureException(fErrors);
   }
}

We can see in the evaluate method that any errors that are thrown during the executing of the test are collected in fErrors. fErrors is used at the end of the evaluate method to create and throw a new MultipleFailureException, which will notify our FailureListener. The crucial part for us is that despite an error being thrown during the execution of a test, the @After method will always be attempted in the finally block, and at that point we are blissfully unaware that the test has failed. Hmph.

Our solution, the quickest one to restore functionality (and not use anything deprecated), has been to create a custom RunAfters class that notifies our FailureListener of any errors in the catch block (see above). It seems less than ideal to have to do this, especially since the changes to the RunAfters class are so minor. Perhaps the next JUnit version will do something else…

Written by lizdouglass

September 6, 2008 at 6:16 am