Search
Calendar
March 2024
S M T W T F S
« Sep    
 12
3456789
10111213141516
17181920212223
24252627282930
31  
Your widget title
Archives

Posts Tagged ‘TDD’

PostHeaderIcon Training: Test Driven Development and Unit Testing Cooking Book

Last Tuesday I led a training session about Test Driven Development (TDD) in general, and Unit Tests in particular. I presented a series of best practices related to unit tests, as a set of “receipts”.
The target audience is developpers, either Java coders or other ones. The exercises have no interest from a Java perspective, but are intented at teaching the main concepts and tricks of unit testing.

The exercices are the following:

  • basics
  • methods within methods
  • layers and mocks
  • private methods
  • exceptions
  • loggers
  • new Date()

Here is the presentation:

The original OpenOffice file is hosted by GoogleDocs: Test Driven Development and Unit Testing Cooking Book

The source code of exercises and corrections are available at this link.

PostHeaderIcon How to export Oracle DB content to DBUnit XML flatfiles?

Case

From an Agile and TDD viewpoint, performing uni tests on DAO is a requirement. Sometimes, instead of using DBUnit datasets “out of the box”, the developper need test on actual data. In the same vein, when a bug appears on production, isolating and reproducing the issue is a smart way to investigate, and, along the way, fix it.
Therefore, how to export actual data from Oracle DB (or even MySQL, Sybase, DB2, etc.) to a DBUnit dataset as a flat XML file?

Here is a Runtime Test I wrote on this subject:

Fix

Spring

Edit the following Spring context file, setting the login, password, etc.

<?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-2.5.xsd">

    <!-- don't forget to write this, otherwise the application will miss the driver class name, and therfore the test will fail-->
    <bean id="driverClassForName" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
        <property name="targetClass" value="java.lang.Class"/>
        <property name="targetMethod" value="forName"/>
        <property name="arguments">
            <list>
                <value>oracle.jdbc.driver.OracleDriver</value>
            </list>
        </property>
    </bean>
    <bean id="connexion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"
          depends-on="driverClassForName">
        <property name="targetClass" value="java.sql.DriverManager"/>
        <property name="targetMethod" value="getConnection"/>
        <property name="arguments">
            <list>
                <value>jdbc:oracle:thin:@host:1234:SCHEMA</value>
                <value>myLogin</value>
                <value>myPassword</value>
            </list>
        </property>
    </bean>

    <bean id="databaseConnection" class="org.dbunit.database.DatabaseConnection">
        <constructor-arg ref="connexion"/>
    </bean>
    <bean id="queryDataSet" class="org.dbunit.database.QueryDataSet">
        <constructor-arg ref="databaseConnection"/>
    </bean>
</beans>

The bean driverClassForName does not look to be used ; anyway, if Class.forName("oracle.jdbc.driver.OracleDriver") is not called, then the test will raise an exception.
To ensure driverClassForName is created before the bean connexion, I added a attribute depends-on="driverClassForName". The other beans will be created after connexion, since Spring will deduce the needed order of creation via the explicit dependency tree.

Java

public class Oracle2DBUnitExtractor extends TestCase {
    private QueryDataSet queryDataSet;

    @Before
    public void setUp() throws Exception {
        final ApplicationContext applicationContext;

        applicationContext = new ClassPathXmlApplicationContext(
                "lalou/jonathan/Oracle2DBUnitExtractor-applicationContext.xml");
        assertNotNull(applicationContext);

        queryDataSet = (QueryDataSet) applicationContext.getBean("queryDataSet");

    }

    @Test
    public void testExportTablesInFile() throws DataSetException, IOException {
    // add all the needed tables ; take care to write them in the right order, so that you don't happen to fall on dependencies issues, such as ones related to foreign keys
    
        queryDataSet.addTable("MYTABLE");
        queryDataSet.addTable("MYOTHERTABLE");
        queryDataSet.addTable("YETANOTHERTABLE");

        // Destination XML file into which data needs to be extracted
        FlatXmlDataSet.write(queryDataSet, new FileOutputStream("myProject/src/test/runtime/lalou/jonathan/output-dataset.xml"));

    }
}

PostHeaderIcon How to unit test Logger calls?

Case

Sometimes, you need test the Log4J’s loggers are called with the right parameters. How to perform these tests from with JUnit?

Let’s take an example: how to test these simple class and method?

public class ClassWithLogger {
    private static final Logger LOGGER = Logger.getLogger(ClassWithLogger.class);

    public void printMessage(Integer foo){
        LOGGER.warn(&quot;this is the message#&quot; + foo);
    }
}

Example

Define an almost empty Log4J appender, such as:

public class TestAimedAppender extends ArrayList&lt;String&gt; implements Appender {
    private final Class clazz;

    public TestAimedAppender(Class clazz) {
        super();
        this.clazz = clazz;
    }

    @Override
    public void addFilter(Filter newFilter) {
    }

    @Override
    public Filter getFilter() {
        return null;
    }

    @Override
    public void clearFilters() {
    }

    public void close() {
    }

    @Override
    public void doAppend(LoggingEvent event) {
        add(event.getRenderedMessage());
    }

    @Override
    public String getName() {
        return &quot;TestAppender for &quot; + clazz.getSimpleName();
    }

    @Override
    public void setErrorHandler(ErrorHandler errorHandler) {
    }

    @Override
    public ErrorHandler getErrorHandler() {
        return null;
    }

    @Override
    public void setLayout(Layout layout) {
    }

    @Override
    public Layout getLayout() {
        return null;
    }

    @Override
    public void setName(String name) {
    }

    public boolean requiresLayout() {
        return false;
    }
}

Then create a TestCase with two fields:

public class ClassWithLoggerUnitTest {
    private ClassWithLogger classWithLogger;
    private TestAimedAppender appender;
...
}

In the setup, remove all appenders, create an instance of our appender, and then add it to the logger related to the class which we want to test:

    @Before
    public void setUp() throws Exception {
        final Logger classWithLoggerLogger = Logger.getLogger(ClassWithLogger.class);
        classWithLoggerLogger.removeAllAppenders();
        appender = new TestAimedAppender(ClassWithLogger.class);
        classWithLoggerLogger.addAppender(appender);
        appender.clear();

        classWithLogger = new ClassWithLogger();
    }

Then write the following test. The code is documented:

    @Test
    public void testPrintMessage() throws Exception {
        final String expectedMessage = &quot;this is the message#18&quot;;

        // empty the appender
        appender.clear();
        // check it is actually empty before any call to the tested class
        assertTrue(appender.isEmpty());

        // call to the tested class
        classWithLogger.printMessage(18);

        // check the appender is no more empty
        assertFalse(appender.isEmpty());
        assertEquals(1, appender.size());
        // check the content of the appender
        assertEquals(expectedMessage, appender.get(0));

    }

Conclusion

This basic example shows how to perform tests on logger, without overriding the original code or using mocks. Of course, you can improve this basic example, for instance in discriminating owing to the log level (INFO, WARN, ERROR, etc.), use generics, and even any other fantasy ;-).

PostHeaderIcon No source code is available for type org.junit.Assert; did you forget to inherit a required module?

Case

You run a GWT application, with a a service layer. Those services are tested through unit tests, which may use EasyMock, among other frameworks. Of course, you hinted at related jars, such us JUnit, by a <scope>test</scope> in your pom.xml.

Yet, when you run the GWT application with a Jetty light container, you get the following message:

Compiling module lalou.jonathan.gwt.client.MyModule

Validating newly compiled units

[ERROR] Errors in 'file:/C:/eclipse/workspace/.../test/unit/lalou/jonathan/gwt/client//MyServiceUnitTest.java'
[ERROR] Line 26: No source code is available for type org.easymock.MockControl; did you forget to inherit a required module?
[ERROR] Line 76: No source code is available for type org.junit.Assert; did you forget to inherit a required module?

Fix

Since Maven2 and GWT scopes are fully independant, you have to modify you *.gwt.xml. Replace:

 &lt;source path='client'/&gt;

with:

&lt;source path='client' excludes=&quot;**/*UnitTest.java,**/*RuntimeTest.java&quot;/&gt;

NB: Never forget that Google teams work with Ant, and not with Maven!