Hudson comes with a test harness built around JUnit to make test development simpler. This harness provides the following features:
The following code shows a very simple test case. Your test will extend from HudsonTestCase instead of standard TestCase. HudsonTestCase defines additional code that provides some of those features outlined above.
Each test method will start with a fresh temporary installation of Hudson. The test1 method doesn't request any particular Hudson dataset to seed Hudson, so it will start from an empty installation.
The test then proceed to create a new project and set it up. As you can see, the code directly talks to the in-memory Hudson object model (There is the protected 'hudson' variable defined in HudsonTestCase that you can use for access.) While you can do the same by emulating the user HTTP interaction through HtmlUnit, this way is often a convenient way to prepare an environment for the code that you want to test.
The test code in this example then switch to HtmlUnit to emulate the UI interaction and verify that we get results that we expect.
When a test completes, the temporary Hudson installation will be destroyed.
When preparing you virtual test environment, you may wish to simulate Hudson environment variables that can be set on the Hudson configuration page. Adding environment variables to a Hudson instance before a test is simple, as the example below demonstrates.
Your IDE would most likely have an ability of selecting a single JUnit test and execute it in the debugger. Otherwise you can run mvn -Dmaven.surefire.debug -Dtest=hudson.SomeTest test to run a test with the debugger.
To debug slaves launched by Hudson, set -Dorg.jvnet.hudson.test.HudsonTestCase.slaveDebugPort=PORT to the system property, or from your test case set HudsonTestCase.SLAVE_DEBUG_PORT to a non-0 value.
Sometimes you want to have quick tests which don't starts up a 'full' Hudson instance as HudsonTestCase does as this can take some time. In that case you shouldn't have your test classes extend HudsonTestCase.
As creating most Hudson core classes without a Hudson instance is unfortunately not easy;mocking can come in handy. One excellent mocking framework is e.g. Mockito. For example, if you want to mock a build with a certain result you could do:
If you'd like to test the HTML generated by Hudson, XPath test is often convenient.
So you'd have to look for the corresponding HtmlButton element, then use that to call the submit method, like this:
The original HtmlUnit doesn't really do a good job of chaining all exceptions together, so we are patching HtmlUnit to make sure it retains the full stack trace leading up to the root cause. If you found a case where this chain is broken, please file a bug.
This test ensures that your configuration page is properly pre-populated with the current setting of your model object, and it also makes sure that the submitted values are correctly reflected on the constructed model object. To be really sure, do this twice with different actual values — for example, you should try a non-null string and null string, true and false, etc., to exhaust representative cases.
HtmlUnit has a WebAssert class that can be used for simple assertions on HTML pages.
To assert that the System configuration page contains the CVS SCM configuration entry:
TestCase as an RootAction
Instance of the test case being executed is added to Hudson's URL space as /self because HudsonTestCase is itself a RootAction. Among other things, this enbles your test class to define Jelly views, and invoke it like createWebClient().goTo("self/myview").
You can extend TestBuilder to write a one-off builder that can coordinate with your test. This is often convenient to stage things up for testing your Publisher, for example by placing files in the workspace, etc.
OneShotEvent is also often an useful companion so that the thread that runs your test method and the thread that runs the build can coordinate — for example, the following program have the main thread block until a build starts.
During the test, one might want to register extensions just during that particular test, for example to assist the test scenario. You can do this by defining such extension as a nested type of your test case class and put TestExtension instead of Extension.
It lets you tie an extension to just one test method, or all test methods on the same class.
There are several annotations in the Hudson test framework.
Issue tracker number for the test.
Production classes that tests are related to. Useful when the relationship between the test class name and the test target class is not obvious.
URL to the web page indicating a problem related to this test case.
The specified class will be used to set up the test environment using HudsonTestCase.
Runs a test case with a data set local to test method or the test class.
This recipe allows your test case to start with the preset HUDSON_HOME data loaded either from your test method or from the test class.
Search is performed in this specific order. The fall back mechanism allows you to write one test class that interacts with different aspects of the same data set, by associating the dataset with a test class, or have a data set local to a specific test method.
The choice of zip and directory depends on the nature of the test data, as well as the size of it.
Runs a test case with one of the preset HUDSON_HOME data set:
Installs the specified plugin before launching Hudson in the test. For now, this has to be one of the plugins statically available in resources "/plugins/NAME".