Documentation & Tutorials

Try a tutorial to get you started with Integrity, or read about some of the more advanced features.

Advanced Topics: Advanced Fixture Techniques

The Integrity Framework is specifically designed for seamless integration into your custom project infrastructure and test creation workflows. Fixtures are the glue between your application and your test scripts, but they can also be a link between your application and the Integrity test script editor in that they can provide - for example - suggestions for possible parameter values which are then offered during script editing.

There are at the moment three types of "advanced" fixtures (which can be combined, as they are actually extensions of a simple, basic fixture):

  • Arbitrary Parameter/Result Fixtures - these allow you to accept additional parameters (besides those with fixed, predefined names, which are determined from the parameters of the fixture methods) as well as additional results
  • Custom Proposal Fixtures - you can use those to supply dynamically generated autocompletion suggestions for any (arbitrary or fixed) fixture parameters
  • Custom Comparator Fixtures - these allow to override the matching algorithm used when checking a fixture-determined result against the expected result given by the test script

Arbitrary Parameters

Normally, fixture methods specify a limited number of parameters, each of them with a unique name that is attached to the parameter using the @FixtureParameter annotation. These parameters also specify their expected data types implicitly via the Java types that are used. At script edit time, Integrity can thus check whether a fixture parameter used in a script actually exists, valid parameters can be suggested/autocompleted and depending on the parameter type it may even be able to propose valid values, such as with enumerations. If you provide good Javadoc coverage of your fixture methods, you will even notice that not only the fixture method calls are being equipped with the corresponding comments, but even the parameters are enriched with the comment texts that were written to explain these parameters in the fixture code.

But what if you cannot specify all parameters of a fixture method in advance? That's where arbitrary parameters come into play! Since good, practical examples for such a fixture tend to be of the more complex nature - think for example about one that inspects a provided Java class and accepts a value for each class attribute - I will use a simple, fictional example here.

Arbitrary parameter fixtures are actually comprised of two parts: 

  1. A fixture that implements the interface ArbitraryParameterFixture
  2. An additional, separate class that implements the interface ArbitraryParameterEnumerator

The idea of this split is simple: while the fixture class contains everything required at test execution time, the enumerator class isn't required during execution, but only during test edit time, since it contains the code responsible for creating the autocompletion proposals, help texts et cetera. This actually means that the second class will be dynamically loaded right from your workspace into your running Eclipse VM at test edit time, where it will be instantiated and called! So you effectively have all the Eclipse-internal tools at your disposal when writing the code for that class, like JDT-based class inspection mechanics and stuff.

The link between the enumerator and the fixture class is done via the @ArbitraryParameterFixtureLink annotation that is attached to the enumerator class. This allows Integrity to easily discover the enumerator class for a given fixture during editing, while avoiding the introduction of a dependency from the enumerator class to the fixture class - the fixture class can be used without the enumerator at runtime.

Now let's take a look at some code for a fixture class!

public class ArbitraryParameterExample implements ArbitraryParameterFixture {

	@FixtureMethod(description = "This is a simple arbitrary parameter fixture method.")
	public void arbitraryParamMethod(@FixtureParameter(name = "fixedParam") String aFixedParam, Map<String, Object> someMoreParams) {
		// do something useful here
	}

	@Override
	public Map<String, Class<?>> defineArbitraryParameters(
			String aFixtureMethodName, Map<String, Object> someFixedParameters) {
		Map<String, Class<?>> result = new HashMap<String, Class<?>>();
		result.put("aFirstAdditionalParam", Integer.class);
		result.put("aSecondAdditionalParam", String.class);
		return result;
	}

	@Override
	public Map<String, Class<?>> defineArbitraryResults(
			String aFixtureMethodName, Map<String, Object> someFixedParameters) {
		return null;
	}

}

There are a few things to notice:

  • The method has one fixed param, which is a String and has a name associated to it, as well as a strange Map<String, Object> parameter. The first is a simple, fixed param as we know them, while the second parameter is mandatory for all methods that want to receive arbitrary parameters. This map will be used to transfer all the arbitrary parameters given as well as the associated values, with the name of the parameter mapping to its matching value.
  • There's a defineArbitraryParameters method which gets a fixture method name (that is the name of the fixture method in question for which Integrity needs information about arbitrary parameters) and a map of known fixed parameters. These can be used in the process of determining the valid arbitrary parameters.
  • The return value of the defineArbitraryParameters method is actually a map as well, mapping names of valid arbitrary parameters to Java types. The mapped types are the respective conversion target types, that is, the types into which any values coming from the test scripts are to be autoconverted before being given to the fixture method. Actually, returning these types is the only purpose of this defineArbitraryParameters method here in the fixture! Any arbitrary parameter value given in the test script that will not be mapped to a type by this method will be returned as well, but not be converted at all, thus the fixture will get the framework-internal representation of the value.
  • And then there's actually another, very similar method named defineArbitraryResults. This does belong to the arbitrary result mechanism described a little bit further down in this document. At the moment, both are defined by the same interface, so they always come in pairs. However, you can have the one of them you don't need return null if you want, and I'm already planning on splitting the interface in two parts to get rid of this "forced pair" in a future Integrity version.

Having the code for the actual test execution in place, we turn our attention to the second class we'll need, the enumerator class:

@ArbitraryParameterFixtureLink(ArbitraryParameterExample.class)
public class ArbitraryParameterEnumeratorExample implements ArbitraryParameterEnumerator {

	@Override
	public List<ArbitraryParameterDefinition> defineArbitraryParameters(
			String aFixtureMethodName, Map<String, Object> someFixedParameters) {
		List<ArbitraryParameterDefinition> resultList = new ArrayList<ArbitraryParameterDefinition>();
		resultList.add(new ArbitraryParameterDefinition("aFirstAdditionalParam", Integer.class, "The help text for the first param."));
		resultList.add(new ArbitraryParameterDefinition("aSecondAdditionalParam", String.class, "The help text for the second param."));
		return resultList;
	}

	@Override
	public List<ArbitraryParameterDefinition> defineArbitraryResults(
			String aFixtureMethodName, Map<String, Object> someFixedParameters) {
		return null;
	}

}

This class looks a lot similar to the fixture class, except it doesn't contain the fixture method, of course. And when looking at the details, you will notice that the defineArbitraryParameters method now returns a different result: a list of ArbitraryParameterDefinition objects. Each of these encapsulates one arbitrary parameter, with everything required to display them in the editor:

  • The name
  • The target type
  • The help text to be displayed next to the parameter (and in some other places like mouseover help in the future!)

You can also see the annotation being used to link the enumerator class to the fixture class.

With both of these classes in place, the test script is the last missing piece to take a look at:

packagedef playground with

	calldef arbitraryParamMethod uses integrity.playground.advancedfixtures.ArbitraryParameterExample#arbitraryParamMethod

	suitedef rootSuite with
		call arbitraryParamMethod fixedParam: "foo" +aFirstAdditionalParam: "123" +aSecondAdditionalParam: 456
	suiteend

packageend

Arbitrary Results

...to be continued