Liz Douglass

Posts Tagged ‘JUnit

On mocking and Spring

with one comment

Two weeks ago I was pairing with Alex on some Java integration tests for an application that uses Spring for dependency injection. Whilst writing one of the tests we realised that we needed to mock some behaviour on one of our Spring configured classes. Instinctively the simplest way to do this would be to replace the bean in our application context with another one, but alas after some brief investigation we discovered this is not an option.We ended up using the same pattern that was already in use in our code base, and I’m sure it’s one that some people will be familiar with:

First up we extracted an interface from the class that whose behaviour we wanted to mock:

public interface FooRepository {
    Foo loadFor(XYZ xyz);
}

Next we created a new Application Context XML configuration file to use for the test and included the ‘real’ one from our application. We also defined a stub class that implemented our new interface. It also had the same id as the class that we wanted to mock behaviour for meaning that the pre-existing definition would be overridden:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans.xsd">
 <bean id="FooRepository" class="FooRepositoryStub"/>
 <import resource="applicationContext.xml"/>
</beans>

Now for the behaviour that we want in the test…. Singleton scoped Spring beans are loaded at start-up (unless you have lazy loading which we do not). Hence if we want to be able to define specific behaviour inside a test we can’t use on our stub implementation alone – rather we need to use the stub as a wrapper for a delegate:

public class FooRepositoryStub implements FooRepository {

    private FooRepository delegate;

    public Foo loadFor(XYZ xyz) {
        return delegate.loadFor(xyz);
    }

    public void setDelegate(FooRepository delegate) {
        this.delegate = delegate;
    }
}

The delegate can then be used to provide the mocking that we wanted all along:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")

public class ValidationIntegrationTest {

    @Autowired
    private FooRepository FooRepository;
    private FooRepository FooRepositoryDelegate = mock(FooRepository.class);

    @Before
    public void initializeRepositoryDelegates() {
        ((FooRepositoryStub) FooRepository).setDelegate(FooRepositoryDelegate);
    }

    @Test
    public void shouldInvalidateXYZWhenTheABCRuleIsViolated() {
        XYZ xyz = givenSomeContext();
        andTheUserHoldsFoo(xyz);
        whenSomethingHappends(xyz);
        thenItShouldFailWithReasons(xyz, "XYZ failed because of the ABC rule was violated");
    }

    private void andTheUserHoldsFoo(XYZ xyz) {
        Foo foo = mock(Foo.class);
        when(FooRepositoryDelegate.loadFor(xyz)).thenReturn(foo);
    }
    ....
}

So, with only an interface, another ApplicationContext XML file, a stub and a mock, we can define the behaviour in the test that we wanted (phew)! I’ve used PicoContainer before and only just now realise how easy with had it in setting up tests. Of course there may be an easier way to do all this – and if you have one then I’d love to hear from you.

Written by lizdouglass

August 20, 2009 at 9:47 pm

Posted in Java

Tagged with , , ,

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

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