Automatic Generation of Sequence Diagrams with Yatspec

Currently at Sky we are working on a greenfield project and for our new apps we are generating sequence diagrams from acceptance tests. It is very nice to have an always up to date diagram showing you how your application is working.

Lets start with the dependencies in our pom.xml. This example builds on top of Acceptance testing with Yatspec so you will need all the dependencies listed there. You will also need:

    <!-- This is to make yatspec sequence diagram generator happy -->
    <!-- This is to make yatspec sequence diagram generator happy -->

Yatspec uses captured inputs and outputs to find out what happened in the test and how to render the sequence diagram. If we want Yatspec to do most of the work for must, we have to put things in the captured inputs and outputs in a particular format:

"(.*) from (.*) to (.*)"

For example, the next image


would be generated if we put something like the following this in captured inputs and outputs:

capturedInputAndOutputs.add("Request from a_user to helloWorldApp", request)
capturedInputAndOutputs.add("Response from helloWorldApp to a_user", responseContent);

In our case, we changed the when clause  from Acceptance testing with Yatspec to look like this:

private CapturedInputAndOutputs whenWeMakeARequestTo(CapturedInputAndOutputs capturedInputAndOutputs, HttpGet request) throws IOException {
    capturedInputAndOutputs.add(format("Request from %s to %s", "a_user", "helloWorldApp"), request);
    response = HttpClientBuilder.create().build().execute(request);
    responseBody = EntityUtils.toString(response.getEntity());
    capturedInputAndOutputs.add(format("Response from %s to %s", "helloWorldApp", "a_user"), response.getStatusLine().toString());
    return capturedInputAndOutputs;

That will make our code easier to understand by Yatspec, but it is not enough to actually generate the sequence diagram.

Now we add in the teardown the code to generate the diagram and put it in the captured inputs and outputs.

By implementing the WithCustomResultListeners interface we are telling Yatspec

public void tearDown() throws Exception {
 capturedInputAndOutputs.add("Sequence Diagram", generateSequenceDiagram());

private SvgWrapper generateSequenceDiagram() {
 return new SequenceDiagramGenerator().generateSequenceDiagram(new ByNamingConventionMessageProducer().messages(capturedInputAndOutputs));

The generateSequenceDiagram() function is using taking the captured inputs and outputs and using it to generate an xml that represents the sequence diagram. If we put it in the captured inputs and outputs, it will render something horrible like in the next image:


To make it render a nice diagram, we need to tell Yatspec that our test class will want to put some extra transformations on the output before it is rendered to html. In our case we do that by implementing the interface WithCustomResultListeners.

public class AcceptanceTest extends TestState implements WithCustomResultListeners { ...
public Iterable<SpecResultListener> getResultListeners() throws Exception {
 return singletonList(new HtmlResultRenderer()
 .withCustomRenderer(SvgWrapper.class, new DontHighlightRenderer<>()));

Now we can rerun out test and it will look as expected again:



2 Comments Add yours

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s