Custom containers

In case you have a custom action container implementation you might also want to use it in Java DSL. The action containers are handled with special care in the Java DSL because they have nested actions. So when you call a test action container in the Java DSL you always have something like this:

Java DSL designer and runner

@CitrusTest
public void containerTest() {
    echo("This echo is outside of the action container");

    sequential()
        .actions(
            echo("Inside"),
            echo("Inside once more"),
            echo("And again: Inside!")
        );

    echo("This echo is outside of the action container");
}

Now the three nested actions are added to the action sequential container rather than to the test case itself although we are using the same action Java DSL methods as outside the container. This mechanism is only working because Citrus is handling test action containers with special care.

A custom test action container implementation could look like this:

public class ReverseActionContainer extends AbstractActionContainer {
    @Override
    public void doExecute(TestContext context) {
        for (int i = getActions().size(); i > 0; i--) {
            getActions().get(i-1).execute(context);
        }
    }
}

The container logic is very simple: The container executes the nested actions in reverse order. As already mentioned Citrus needs to take special care on all action containers when executing a Java DSL test. This is why you should not execute a custom test container implementation on your own.

@CitrusTest
public void containerTest() {
    ReverseActionContainer reverseContainer = new ReverseActionContainer();
    reverseContainer.addTestAction(new EchoAction().setMessage("Foo"));
    reverseContainer.addTestAction(new EchoAction().setMessage("Bar"));
    run(reverseContainer);
}

The above custom container execution is going to fail with internal error as the Citrus Java DSL was not able to recognise the action container as it should be. Also the EchoAction instance creation is not very comfortable. Instead you can use a special container Java DSL syntax also with your custom container implementation:

@CitrusTest
public void containerTest() {
    container(new ReverseActionContainer()).actions(
        echo("Foo"),
        echo("Bar")
    );
}

The custom container implementation now works fine with the automatically nested echo actions. And we are able to use the usual Java DSL syntactic sugar for test actions like echo .

In a next step we add a custom superclass for all our test classes which provides a helper method for the custom container implementation in order to have a even more comfortable syntax.

Java DSL designer and runner

public class CustomCitrusBaseTest extends TestNGCitrusTestDesigner {

    public AbstractTestContainerBuilder<ReverseActionContainer> reverse() {
        return container(new ReverseActionContainer());
    }
}

Now all subclasses can use the new reverse method for calling the custom container implementation.

@CitrusTest
public void containerTest() {
    reverse().actions(
        echo("Foo"),
        echo("Bar")
    );
}

Nice! This is how we should integrate customized test action containers to the Citrus Java DSL.