4 Writing a simple JSE JTR-Runner: the fundamental API

Now that all of the most important concepts have been fixed, we can talk about the fundamental APIs the JTR runtime exposes to you for developing your own custom runners and interacting with the JTR runtime.


JTR Runners interfaces hierarchy




The figure above depicts the set of “runner” interfaces defined by the JTR Project. The only interfaces of interest from a developer’s point of view are the following ones:


  1. jtr.runners.IRunner

  2. jtr.runners.IRunnerJMS

  3. jtr.runners.IRunnerWs


Developers must not directly implement these interfaces, instead they must extend one of the following abstract classes provided by the JTR Framework:


  1. jtr.runners.AbstractRunner

  2. jtr.runners.AbstractJMSRunner

  3. jtr.runners.AbstractWsRunner


The choice of which abstract class you should inherit from depends on your needs. In this section we are going to see how to implement a very simple runner that does not need any special JEE feature.


The FailingTest example

In order to implement a really simple runner that always throws an exception, we just need to extend the jtr.runners.AbstractRunner class. Let’s see an example that we are going to comment on later in this section:


package jtr.test.jee.client;


import jtr.runners.AbstractRunner;

import jtr.test.IOutcome;


/**

* This simple runner shows how to enrich outcomes, how exceptions are showed in

* the JTR Console, and how to access the instance-count for the category it belongs

* to.

*

* @author frusso

* @version

* @since

*/

public class FailingTest extends AbstractRunner {

   

    /** Creates a new instance of FailingTest */

    public FailingTest() {

    }


    public void test() throws Throwable {

        throw new RuntimeException("This runner test error reporting.");

    }


    public void receiveFailureNotification(Throwable t, String msg) {

        logger.error("The following error occurred in run/epoch "+getCurrentRun()+

                     "/"+getEpoch());

    }


    public void cleanupResources() {

    }


    public void enrichOutcome(IOutcome outcome) {

        outcome.setUserObject("This is a sample message from the runner "+

                               this.getClass().getSimpleName());

    }

}


The test() method

First of all, we need to provide an implementation for the method:


public void test() throws Throwable


This method encapsulates your testing-logic. In this very simple example it always throws an exception.

Ideally, if during your test you encounter legal-exceptions, that is exceptions that do nor represent an actual error, these exception should be caught by your code. On the other side, this approach does not applies to real-exceptions that represent true error conditions met by your code: you must let these exceptions propagate to the JTR-runtime.


The receiveFailureNotification() method

Once an exception has been caught and handled by the JTR-runtime on your behalf, it is provided to you for further processing by means of the method


public void receiveFailureNotification(Throwable t, String str)


This a notification that something wrong happened during the test execution (a real-exception). You are allowed to do whatever you want in this method with the provided exception since the JTR-runtime has already successfully accomplished its own processing.


The cleanupResources() method

This method is meant for giving runners-developers the ability to dispose resources like opened files and/or JDBC connection in a controlled way.

This method is invoked on every runner instance only once it has been put back in the pool and once it has completed its last run in the last epoch.


The enrichOutcome() method

At the end of each run the JTR-runtime produces an outcome for each of your runner instances. An outcome is defined by the jtr.test.IOutcome interface and stores information about what happened during that run of a that runner.

Every outcome has space for the user to put inside it a user-defined message/object. By means of the


public void enrichOutcome(IOutcome outcome)


method you can do that, as showed in the provided example. Please note that the user-message must be serializable and have a valid string representation.


Completing the example with the jtr.xml file

In order to complete the example let’s show the jtr.xml configuration file that declares the use of the above runner implementation:


<?xml version = '1.0' encoding = 'UTF-8'?>


<!-- JTRunner is free software; you can redistribute it and/or modify

    it under the terms of the GNU General Public License as published by

    the Free Software Foundation; either version 2, or (at your option)

    any later version.

-->


<test xmlns="http://jtrunner.sourceforge.net"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://jtrunner.sourceforge.net file:./config/jtr.xsd"

    runs="10">


    <!-- JTR components factories -->

    <factories>

        <factory key="IAssignmentPolicyFactory"

                 fqn="jtr.assigner.impl.DefaultAssignmentPolicyFactory" />

        <factory key="IOutcomeFactory" fqn="jtr.test.impl.DefaultOutcomeFactory" />

        <factory key="IWsHelperFactory" fqn="jtr.ws.jaxws.JaxWsHelperFactory" />

        <factory key="ITestCompletionListener"

                 fqn="jtr.test.impl.DefaultTestCompletionListener" />

        <factory key="ITestResultDisplayer" fqn="jtr.test.impl.DefaultTestResultDisplayer" />

        <factory key="ITestResultsExporter" fqn="jtr.test.results.exporters.impl.ExcelExporter" />

        <factory key="ITestScriptingEngine" fqn="jtr.script.impl.BshScriptEngine" />

        <factory key="ITestStatFunctions" fqn="jtr.lang.functions.impl.DefaultStatFunctionsFactory" />

    </factories>


    <!-- Runners -->   

    <runner runs="1">

        <runner-fqn>jtr.test.jee.client.FailingTest</runner-fqn>

        <instance-count>2</instance-count>

        <parameters-assignment-policy>

            indexed

        </parameters-assignment-policy>

        <parameters>

            <param name="sleepTime" value="300" />

        </parameters>

        <parameters>

            <param name="sleepTime" value="200" />

        </parameters>

    </runner>

</test>


As we can see, the current test will consist of 10 epochs, 1 runner category declaring 2 instances that will run 1 time per epoch, sleeping respectively for 300 milliseconds and 200 milliseconds.



Next step: writing a simple EJB-enabled JTR-Runner