0

Context/Scenario:

I am using JUnit along with Apache Log4J to learn TDD and Logging services best practices. I have a GenericTaskInterpreter class which has a method connectToMySQL which will attempt to connect to a MySQL database and return an object of type java.sql.Connection.

class GenericTaskInterpreter {

    /**
    * This method will attempt to connect to a MySQL database
    * and return an object of type java.sql.Connection
    */
    public Connection connectToMySQL() {
        Connection connection = null;
        try {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/TestDatabase", "root",
            "password");
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }
}

And I have a class GenericTaskInterpreterTests where I have written the test cases for this method(and other methods).

public class GenericTaskInterpreterTests extends TestCase {

    private static final GenericTaskInterpreter genericTaskInterpreter = new GenericTaskInterpreter();

    private static final Logger logger = LogManager.getLogger(GenericTaskInterpreterTests.class);

    private static boolean setUpIsDone = false;

    private static boolean tearDownIsDone = false;

    private static FileAppender fileAppender;

    @Rule
    public TestRule watchman = new TestWatcher() {

        private String watchedLog;

        // Overridden methods apply, succeeded, skipped, starting and finished....

    };

    protected void setUp() throws Exception {
        if (setUpIsDone) {
            return;
        }
        // Do the setup.
        fileAppender = new FileAppender();
        fileAppender.setName("FileLogger");
        fileAppender.setFile("/path/to/log4j-application.log");
        fileAppender.setLayout(new PatternLayout("%d %-5p [%c{1}.%M] %m%n"));
        fileAppender.setThreshold(Level.DEBUG);
        fileAppender.setAppend(true);
        fileAppender.activateOptions();

        LogManager.getRootLogger().addAppender(fileAppender);
        setUpIsDone = true;
        //logger.info("####### All configurations complete... #######");
        logger.info("####### Starting test cases... #######");

    }

    protected void tearDown() throws Exception {

        if (tearDownIsDone) {
            return;
        }
        // Do the teardown.
        //fileAppender.close();
        LogManager.getRootLogger().removeAppender(fileAppender);
        tearDownIsDone = true;   
    }

    public void testconnectToMySQLIfConnectionObjectIsNotNull() {
        assertNotNull(genericTaskInterpreter.connectToMySQL());
    }
}

Questions:

  • How to use TestWatcher for logging assertion failures in this test case scenario?
  • Is there a better alternative than using TestWatcher?
Sandeep Chatterjee
  • 3,220
  • 9
  • 31
  • 47

2 Answers2

2

You may like to append a common/discrete results file when any of the events (setup ,test,cleanup failure/pass/skip) happen .

If you are running your tests parallel you have have to synchronize the logging writes to the results file

To do this you may have to override the methods in RunListener from junit API

http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html of class RunListener

Puneet
  • 113
  • 5
1
@Rule
public TestRule watchman = new TestWatcher() {

    @Override
    protected void succeeded(final Description description) {
        logger.info(String.format("Success: %s", description));
    }

    @Override
    protected void failed(final Throwable e, final Description description) {
        logger.info(String.format("Failed: %s", description), e);
    }

    @Override
    protected void starting(final Description description) {
        logger.info(String.format("Starting: %s", description));
    }

    @Override
    protected void finished(final Description description) {
        logger.info(String.format("Finished: %s", description));
    }

    };

If you want to write it somewhere, Log4J will do nicely, as you have already done. Personally, I would configure it via file and not use the root logger, but that's just a detail.

Florian Schaetz
  • 10,454
  • 5
  • 32
  • 58
  • `2015-08-12 15:29:17,828 INFO [GenericTaskInterpreterTests.setUp] ####### Starting test cases... #######`. That is the line getting written to the log file and not the messages inside either of `succeeded`, `failed`, `starting` or `finished` methods. – Sandeep Chatterjee Aug 12 '15 at 10:04
  • 1
    You probably have the same problem we had here recently: `extends Testcase` seems to lead to the execution of your Test with the JUnit 3.8 Runner. You can either remove that `extends Testcase` (and use `Assert.assertNotNull`, etc. explicitly, perhaps using static imports) OR you can add the line `@RunWith(BlockJUnit4ClassRunner.class)` to your testclass. See this posting for a similar problem: http://stackoverflow.com/questions/31904380/junit-4-12-issue-testing-exception/31904488#31904488 – Florian Schaetz Aug 12 '15 at 11:58
  • Thanks Florian. I just did what you suggested and it ran fine. Here's the gist to the [working code](https://gist.github.com/sndpchatterjee07/576fa9255e52a01c824d). If I understood it correctly, the annotation `@RunWith(BlockJUnit4ClassRunner.class)` is comparatively of lesser significance than removing `extends TestCase`. – Sandeep Chatterjee Aug 12 '15 at 13:20
  • 1
    You probably shouldn't need both, true. Simply removing the `extends TestCase` should be enough to make it run with the most current Runner. The @RunWith was just a posibility if you wanted to keep the extends. Personally I try to use @RunWith only if really needed, no need to clutter the code. – Florian Schaetz Aug 12 '15 at 13:47