13.6. Testing the build

The freshStart and quickStart targets are the basic ways to build Hackystat. This section focuses on the next step: running the set of JUnit tests on the system to verify that your build is working correctly.

Hackystat JUnit test targets come in two flavors--a "module" version, which invokes the unit tests associated with an individual available module, and an "all" version, which invokes JUnit tests on all available modules.

13.6.1. Running tests: all.junit and <module>.junit

The most convenient way to test the system is with 'ant -q all.junit', which invokes the unit tests associated with all available modules on the built and deployed system. The following listing shows the successful invocation of all.junit target.

c:\svn\hackyCore_Build>ant -q all.junit
     [echo] (11:28:43) Completed hackyCore_Kernel.junit.
     [echo] (11:28:44) Completed hackyCore_Statistics.junit.
     [echo] (11:28:57) Completed hackyCore_Report.junit.
     [echo] (11:29:03) Completed hackyCore_Common.junit.
     [echo] (11:29:10) Completed hackyCore_Telemetry.junit.
     [echo] (11:29:25) Completed hackyCore_Installer.junit.
     [echo] (11:29:25) Completed all.junitReport
     [echo] (11:29:25) Completed all.junit

BUILD SUCCESSFUL
Total time: 1 minute 0 seconds

Another approach is to invoke the unit tests associated with a single module, such as the listing below which invokes the unit tests associated with the hackyCore_Kernel module. In this case, the "-q" option is not used so that you can see more detailed output on the execution of the test cases.

c:\svn\hackyCore_Build>ant hackyCore_Kernel.junit
Buildfile: build.xml

hackyCore_Kernel.junit:
    [junit] Running org.hackystat.core.kernel.util.TestWeek
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.33 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.04 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.03 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.21 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.431 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 1.332 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.471 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.03 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.05 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.991 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0 sec

BUILD SUCCESSFUL
Total time: 8 seconds

In this example, all of the unit tests executed correctly.

13.6.2. Investigating test failures

To show what happens when unit tests don't pass, I created a simple test method that called the fail() method in one of the hackyCore_Kernel test classes:

 public void testFakeFailure() {
    fail("Example failing test case.");
  }
 

The next listing shows how I rebuilt the system with this failing test case and ran all of the unit tests associated with available modules using a single invocation of Ant:

c:\svn\hackyCore_Build>ant -q quickStart all.junit
     [echo] (11:45:31) Completed hackyCore_Build.checkModuleAvailability
     [echo] (11:45:32) Completed hackyCore_Build.hotUndeployHackystat
     [echo] (11:45:34) Completed all.compile
     [echo] (11:45:39) Completed all.install.pre-sensorshell
     [echo] (11:45:42) Completed hackyCore_Build.installSensorShell
     [echo] (11:45:46) Completed all.install.post-sensorshell
     [echo] (11:45:46) Completed hackyCore_Build.deployTestData
     [echo] (11:45:47) Completed hackyCore_Build.hotDeployHackystat
     [echo] (11:45:49) Completed hackyCore_Build.deploySoap
    [junit] Tests FAILED
     [echo] (11:45:59) Completed hackyCore_Kernel.junit.
     [echo] (11:46:00) Completed hackyCore_Statistics.junit.
     [echo] (11:46:09) Completed hackyCore_Report.junit.
     [echo] (11:46:14) Completed hackyCore_Common.junit.
     [echo] (11:46:19) Completed hackyCore_Telemetry.junit.
     [echo] (11:46:32) Completed hackyCore_Installer.junit.
     [echo] (11:46:37) Completed all.junitReport
     [echo] (11:46:37) Completed all.junit

BUILD SUCCESSFUL
Total time: 1 minute 9 seconds

As you can see, the "Tests FAILED" message appears, indicating that something went wrong. In Hackystat, when running tests with the -q option, the next line of output (indicating which module just completed) reveals which module had the failing unit test. In this example, the next line indicates the hackyCore_Kernel.junit completed, which indicates that the failing unit test occurred in the hackyCore_Kernel module.

Let's run just the tests associated with that module without the -q option to see this more clearly.

c:\svn\hackyCore_Build>ant hackyCore_Kernel.junit
Buildfile: build.xml

hackyCore_Kernel.junit:
    [junit] Running org.hackystat.core.kernel.util.TestWeek
    [junit] Tests run: 4, Failures: 1, Errors: 0, Time elapsed: 0.33 sec
    [junit] TEST org.hackystat.core.kernel.admin.TestServerProperties FAILED
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.21 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.431 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 1.342 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.48 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.111 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.981 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests FAILED
TEST org.hackystat.core.kernel.admin.TestServerProperties FAILED

BUILD SUCCESSFUL
Total time: 9 seconds

Invoking the module-level junit target without the -q option reveals which test case failed.

To support diagnosis of junit failures, the Hackystat Build System includes a task called JUnitReport, which takes the XML data generated by JUnit in the case of a failure and creates an HTML report on the failure. The all.junitReport target is invoked automatically as part of the all.junit target (as you can see in the above listing of the all.junit invocation), but is not invoked as part of module-specific junit invocations (as you can see in the above listing of the hackyCore_Kernel.junit invocation).

If you want the JUnitReport associated with a unit test failure, you have two options: (1) invoke all.junit, which generates JUnitReports for all failing test classes automatically, or (2) invoke the module-specific junit task, but add the module-specific junitReport target to that invocation. Here's what option (2) looks like:

c:\svn\hackyCore_Build>ant hackyCore_Kernel.junit hackyCore_Kernel.junitReport
Buildfile: build.xml

hackyCore_Kernel.junit:
    [junit] Running org.hackystat.core.kernel.util.TestWeek
    [junit] Tests run: 4, Failures: 1, Errors: 0, Time elapsed: 0.32 sec
    [junit] TEST org.hackystat.core.kernel.admin.TestServerProperties FAILED
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.03 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.201 sec
    [junit] Tests run: 4, Failures: 0, Errors: 0, Time elapsed: 0.41 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 1.322 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.281 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.04 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 1.042 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.02 sec
    [junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0 sec
    [junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests run: 3, Failures: 0, Errors: 0, Time elapsed: 0.01 sec
    [junit] Tests FAILED
TEST org.hackystat.core.kernel.admin.TestServerProperties FAILED
     [echo] (12:09:46) Completed hackyCore_Kernel.junit.

hackyCore_Kernel.junitReport:
[junitreport] Transform time: 4086ms
     [copy] Copying 1 file to C:\svn\hackyCore_Build\build\reports\junit

BUILD SUCCESSFUL
Total time: 13 seconds

Figure 13.1, “ The top-level JUnitReport for a module with a failing test case ” illustrates the JUnitReport resulting from this build system failure. Note that the URL in this screen shot reveals that this report was loaded from the file named hackyCore_Build/build/reports/junit/hackyCore_Kernel/index.html. In general, the JUnit reports are generated in the build/reports/junit/<module>/ directory.

Figure 13.1.  The top-level JUnitReport for a module with a failing test case


The top-level JUnitReport for a module with a failing test case

Figure 13.2, “ The JUnitReport screen for the failing test case ” illustrates the JUnitReport after drilling down through to the screen reporting on the actual failing test method.

Figure 13.2.  The JUnitReport screen for the failing test case


The JUnitReport screen for the failing test case

13.6.3. Running individual unit tests in Eclipse

When you want to verify that the build is correct, the most robust way is to use "ant -q all.junit". When you are doing new development, the time required to run all of the unit tests may slow down development too much. In this case, using the module-specific junit target (such as hackyCore_Kernel.junit) allows you to run all of the test cases associated with a single module.

In some cases, you may only want to run a single test case. This is also possible for Hackystat if you are using an integrated development environment such as Eclipse. The process is to set up a test using the normal IDE mechanisms in Eclipse, and provide three JVM arguments that specify the location of the hackystat war directory, the Tomcat installation, and the directory containing the hackystat.build.properties file. Figure 13.3, “ The Eclipse JUnit invocation configuration window ” illustrates the JUnit run configuration window in Eclipse with these three JVM properties set correctly for one developer's environment.

Figure 13.3.  The Eclipse JUnit invocation configuration window


The Eclipse JUnit invocation configuration window

Figure 13.4, “ The Eclipse JUnit invocation results window ” illustrates the Eclipse window resulting from the invocation of the single JUnit test defined above.

Figure 13.4.  The Eclipse JUnit invocation results window


The Eclipse JUnit invocation results window

There are a couple of important things to know when running unit tests directly within Eclipse.

First, when you run a Hackystat unit test within Eclipse, you may get one or more error messages in the console window similar to the following:

05/30 06:05:09 Error defining an SDT in java.io.FileInputStream@a4e2e3:
org.hackystat.core.kernel.sdt.SensorDataTypeException: Undefined wrapper class org.hackystat.sdt.bufftrans.sdt.BuffTrans
	at org.hackystat.core.kernel.sdt.SensorDataType.findWrapperConstructor(SensorDataType.java:145)
	at org.hackystat.core.kernel.sdt.SensorDataType.<init>(SensorDataType.java:42)

As you can see, the Eclipse environment could not find the definition of a Hackystat sensor data type. Depending upon what you're actually testing, this error may or may not affect the outcome of the unit test. If you're not testing a feature that actually has to manipulate that SDT, then you can probably ignore the error.

If you need Eclipse to know about that SDT, then you have to modify the properties for the Eclipse project containing your unit test to put the hackystat module containing the SDT into its build path. Figure 13.5, “ The Eclipse Java Build Path window ” illustrates the Eclipse Project "Java Build Path" window where you can add Hackystat SDT modules.

Figure 13.5.  The Eclipse Java Build Path window


The Eclipse Java Build Path window

This figure illustates the build path for the hackySdt_FileMetric module. As you can see, it has one dependent SDT Eclipse project: hackySdt_Activity. That means that the Activity SDT will be found and available when any unit tests in the hackySdt_FileMetric project are run. Conversely, it also means that Eclipse will signal an error to the console window if it finds XML definition files for any other SDT definitions in the hackystat.war.dir area.

In general, the Eclipse project definitions are set up so that any dependent projects needed at compile time are on the build path. This does not necessarily include all dependent projects that may be encountered under any conditions at run-time. When you encounter the console error related to an unknown SDT, it may simply be due to the fact that you have many more SDTs in your build configuration than you actually need for the purposes of your unit testing. In this case, you can just ignore the console error messages. On the other hand, if your unit tests fail and the cause is directly related to the lack of an SDT, then of course you should update the Project's build path to include the Hackystat module containing the SDT definition.

The second point to note about running unit tests within Eclipse relates to unit tests that interact with a running Hackystat web server. When running such unit tests, you must remember to rebuild and redeploy your Hackystat web application after updating the source code using either quickStart or freshStart. Otherwise, you may not see your changes to the code reflected in the application's behavior during your test run!

13.6.4. Summary

This section has provided an introduction to the Ant and Eclipse-based approaches to invoking the test code associated with Hackystat. The next section looks at some of the remaining build targets of use to developers.