documenting test architecture

Documenting test architecture: Part 3 – There’s even a better way to draw your framework

Alright, ladies and gentlemen, we’ve recently discussed documenting test architecture and creating a system landscape diagram for the continuous testing process using the Structurizr tool. If you remember, we started with just 2 boring blocks on the initial chart (a QA engineer and the app under test), But in the end, it grew into a colourful well-structured diagram that sheds light on a testing setup.

With all its benefits, there’s one drawback though – there’s not much information about any of the participating systems. For instance, we still don’t know how the test automation framework is built. Having these insights would be very useful because most of the developers and test automation engineers are interested in the test automation framework internals as maintainers.

The C4 model and Structurizr, however, have a solution for this problem, and in today’s article, I am going to walk you through its steps. Hopefully, in the end, we’re going to have an even better-documented test architecture and continuous testing process. Let’s go!

This post is a part of the series. To check the other parts, please visit the links below:

Documenting test architecture: Part 1 – Is there a right way?
Documenting test architecture: Part 2 – There is a Right Way!

Containers but not the Docker ones

If you remember the previous article, the Structurizr DSL’s workspace contains 2 key sections: the model and the views. In the model section, we describe elements of the diagram and their relationships, while in the views section, we describe diagram views and their appearance (styles).

So, in the C4 model, our test automation framework internals diagram would be different, with a more detailed level of abstraction than the system landscape that represents our “big picture” of the entire continuous testing process. In fact, in the terminology of the C4 model, the next level is called the container diagram.

Let’s describe it in Structurizr. The following snippet adds a container view to the DSL model:

views {
   # Existing view
   systemlandscape "SystemLandscape" {
       include *

   # Newly added container
   container testAutomationFramework "Containers" {
       include *
       description "The diagram of the Test Automation Framework architecture"

There is nothing new in the notation of the just-added container, and the text labels are pretty self-explanatory. Let’s save the file and refresh the Structurizr page:

Hey, there’s another view added to the project in the left panel! It is apparently empty because we haven’t added any elements to it yet. However, you can already go back to the system landscape view, double-click on the Test Automation Framework, and Structurizr will navigate you to the automation framework internals (namely, the container view we’ve just created).

Let’s do even more fun.

Architects architect architecture

When someone asks me, what I do as a test architect, I usually reply: “Architects architect architecture”. This is one of my favourite work-related expressions that I, by the way, discovered during Simon Brown’s workshop last year. Since then, I occasionally utilise it in informal conversations.

Let’s then justify this expression and describe a typical architecture of a test automation framework for backend testing. It usually consists of the following components:

  • An abstract layer that handles communication with the microservice under test (so-called HTTP- or REST API client);
  • A business layer that describes the functionality of the microservice under test and utilises the just described REST client to perform calls to relevant endpoints;
  • A test layer that in its turn uses methods of the business layer to build testing scenarios and extract data for assertions;
  • Data models that describe different data entities and simplify building requests and parsing responses;
  • Test data that is supplied to tests and used for building relevant testing scenarios, expected and actual results;
  • Various configuration files for different purposes. But for simplicity, let’s just stick to the configuration of the CI system (like gitlab-ci.yml or *.properties files);
  • A logging framework that simplifies debugging and troubleshooting of tests.

Describing all the above-mentioned in the Structurizr DSL manner is very simple and is all about defining new elements:

group "Continuous Testing Setup" {
   ci = softwaresystem "CI/CD system" "Jenkins: triggers test pipelines, build and stores artifacts" "CI"

   # Newly added code
   testAutomationFramework = softwaresystem "Test Automation Framework" "contains autotests, CI configuration and other utilities" "Automation" {
       abstractLayer = container "Abstract (core) layer" "provides interfaces to communicate via REST API" "RestAssured"
       businessLayer = container "Business (service) layer" "replicates business logic of the app-under-test"             
       testLayer = container "Test layer" "functional test scenarios" "Kotest"
       dataModels = container "Data models" "contains models of data used in the framework"
       testData = container "Test data" "contains data used in the tests"
       configuration = container "CI configuration" "contains the configuration of CI pipeline and jobs"
       logging = container "Logging" "provides logging of the test execution and HTTP requests/responses" "SLF4J" 
   reporting = softwaresystem "Reporting System" "test automation reports and dashboards" "Reporting"

In the snippet above, I converted the testAutomationFramework element into a group and described all its internal elements inside the curly brackets.

After re-rendering the changed workspace.dsl file with Structurizr and re-arranging the default layout of the container diagram a bit, I got the following result:

Now we know what are the components of the test automation framework but still have no clue how they interact with each other. Let’s fix it by introducing relationships between the new elements and also between some of the existing and new ones:

# Relationships with external systems
businessLayer -> applicationUnderTest "sends API calls"
applicationUnderTest -> businessLayer "receives API responses"
businessLayer -> serviceDatabase "fetches data for extra assertions"
configuration -> ci "supplies pipeline and jobs configuration"
logging -> reporting "data for test reports"

# Internal relationships within the test automation framework
abstractLayer -> businessLayer "provides custom Rest API client" "" "Internal"
businessLayer -> testLayer "provides methods to build functional flows" "" "Internal"
testData -> dataModels "provides serializing/deserializing of test data" "" "Internal"
dataModels -> businessLayer "supplies data for requests" "" "Internal"
dataModels -> testLayer "supplies expected data for assertions" "" "Internal"
abstractLayer -> logging "captures backend communication" "" "Internal"
testLayer -> logging "test execution events" "" "Internal"

Did you notice the “Internal” tag added for each relationship from the second group? While grooming the new changes, I realized that the default styling doesn’t make the container diagram easy to read. So, a bit of style tuning for the “Internal”-tagged relationships should do the magic:

relationship "Internal" {
   color #F0F4C3
   fontSize 32
   dashed false

The final test automation framework container diagram with all changes is depicted below:

Internal relationships between the framework’s parts are shown as solid lines, and those few connections with the external systems (CI, app under test, database and reporting solution) are shown as dashed lines for better visibility.


The biggest takeaway of this article (at least for me) is that the C4 model actually works. In the previous post, I had the system landscape diagram, however, there was no connection to how the internals of a particular system looks like.

In this article, I tried to fill that gap by describing the container diagram of my imaginary test automation framework. And now it’s possible to jump between 2 different levels of abstraction via double-click in Structurizr. Just as simple as that:

In the same way, it is possible to describe how other systems in your continuous testing process are built (for example, your CI or reporting setup), and then have everything in one place, reachable within a couple of clicks.

But if we put the toolkit aside, the main question that I asked myself was – does it help me as a test architect to explain to people how my testing setup works, and how it’s built? I think it does.

Does it help my crew to onboard people and, hence, decrease the time needed for new joiners to start contributing faster? I believe it does.

Well, then the game was worth the candle. I’m definitely going to re-use the discoveries of this series in my real projects. There’re a few more features of Structurizr I’d want to explain, and I might be also digging into the remaining abstraction layers of the C4 model. Stay in touch to make sure you won’t miss any new posts.