Writing your first test with junit-objects

This guide will give you a proper overview of building a JO test from scratch, similar to the SampleObjectTest packaged with the JO release. The test will be run programmatically via a main() method.

It is important to remember to clean your build directories every time you run a test. Tests will fail erroneously if you dont. This is why Ant is stronglyrecommended to build and run tests.

Hint: Use the target "sample" in the packaged build.xml as a template for running your tests.

Setting Up the Test

OK, assuming that you followed the steps in the Getting Started guide and were able to build JO and run the sample test, we can get started! Let's begin with a simple test. Assume this is the class you want to test:

MyObject.java

public class MyObject {
    private Boolean boolField;
    private String myString;

    //getters/setters (not strictly necessary)
    //...

    public void doSomething() {
        this.boolField = true;
        this.myString = "junit-objects";
    }

    //etc.
    public void doSomethingElse() {...}
}

This is a fairly simple class, it has 2 properties which are null to begin with and get set to values when the method doSomething() is called. Let's say our test, then, should test the values of these properties after the method call to see if it has behaved right. To do so, lets create a "test descriptor" file called mytest.objects.xml. In it, define yourself a picture of MyObject at runtime (specifically, after doSomething() has been called) like so:

mytest.objects.xml

<junit-objects>
    <object-state name="myState1">
    
<boolField>boolean:true</boolField> <myString>regex:[junit]{4}-[objects]*</myString>
</object-state> </junit-objects>

This is called a state-descriptor (or object-state assertion). A state-descriptor can be thought of as a kind of template for an object, or more practically, an atomic step in a test sequence. Now, you create your ObjectTestCase (similar to a junit TestCase). In it define a metaphor that mimics a unit of your application (in this case the method doSomething()), that you want to test:

MyObjectTest.java

@Objects("mytest.objects.xml")	//notice the descriptor binding
public class MyObjectTest extends ObjectTestCase {
	private MyObject m;

	@Metaphor
	public final void testSomething() {
		m = new MyObject();

		m.doSomethingElse("with a param");
		m.doSometing(); 
	}
}

The metaphor testSomething() creates an instance of MyObject, then calls doSomething(). Note that doSomethingElse() is called too, even though it is not under test. The reason for this is that doSomethingElse() may have an unseen side-effect that disturbs the unit being tested. By mimicing what happens in the real application (i.e. building an "authentic metaphor"), such externalities can be detected and corrected easily. It also helps to ensure regression integrity (for example, if the implementation of doSomethingElse() changes improprietously, it will cause this test to break).

Finally, add a test-sequence (state-chain) to the JO test descriptor:

mytest.objects.xml

<junit-objects>
    <object-state name="myState1">
        <boolField>boolean:true</boolField>
        <myString>regex:[junit]{4}-[objects]*</myString>
    </object-state>

    
<!-- Test MyObject with a state-chain --> <state-chain class="MyObject" metaphor="testSomething" name="myFirstTest"> <trigger method="doSomething" class="MyObject"/> <state refid="myState1"/> </state-chain>
</junit-objects>

Now, running the unit test will ensure that immediately after m.doSomething() is called in the metaphor (testSomething()), the state myState1 is triggered, which asserts that m's boolField is true and that myString contains the value"junit-objects".

Running the test

Currently the only way to run a test is programmatically (Ant and UI is under works). To run your test, add a main() method to your ObjectTestCase that will invoke the JO test runner on your test:

MyObjectTest.java

import com.wideplay.junitobjects.ObjectsBackplane;
import com.wideplay.junitobjects.Tester;

@Objects("mytest.objects.xml")  //notice the descriptor binding
public class MyObjectTest extends ObjectTestCase {
    private MyObject m;

    @Metaphor
    public final void testSomething() {
        m = new MyObject();

        m.doSomethingElse("with a param");
        m.doSometing();
    }

    
public static void main(String a[]) { //retrieve a simple CLI tester from the JO backplane Tester tester = ObjectsBackplane.getObjectTester(MyObjectTest.class); tester.run(); }
}

Now you can run your test and it should validate m's state correctly. Try playing with the protocols to see how you can write more complex assertions. The sample test.junitobjects package that comes with JO source is a good starting point. It shows 7 different ways to assert on a Boolean property. Good luck! =)

See also

  • object-states - Describes semantics of state-descriptors and assertion protocols
  • metaphors - Describes how metaphors work and what should or should not go in them
  • state-chains - A guide to writing test-sequences and chaining states together
  • protocol guide - A guide to the various testing protocols
  • object-profiles - Advanced JO: asserting design-patterns and testing for anti-patterns
  • entropy-profiles - Advanced JO: how to use JO to root out design clutter in your code
Note: JO-Beta requires ALL builds to be clean (.class files must be freshly built from javac). Due to the bytecode instrumenting that JO does (and the design of runtime metaphors) running a JO test twice in a row (without a clean) WILL result in faulty behavior. Ant is recommended to build and run tests.
GetJava Download Button
SourceForge.net Logo
Support This Project