Testing (Camunda)-DMN Tables automatically

Working with DMN Tables is quite easy. It is like working with an Excel Spread Sheet. The idea is that the business people define the Business Rules with these tables.

Wildspitz Switzerland

So why should you bother testing them?

To convince business people to start working Test-Driven, looks to me not very promising.

So let’s build a Tool that makes testing DMN tables a breeze😀

And this is what this blog is all about. How can you use this DMN Tester that tries to adhere to these three goals.

Requirements

You can use the Tester as an JAVA-Application or in a Docker Container.

At the moment I only tested the tool on Mac. So the steps needed are the ones for Mac Users. However in the end we start a standard JAVA application that should also run on Windows.

See the chapter Docker Setup if you want to use the Tester in a Docker Container.

Install Ammonite

Update 22.2.2021: I removed the Ammonite Script for the Demo Project — so please use the Docker Setup to use the DMN Tester.

Ammonite we use to easily install, configure and start the DMN Tester.

$ brew install ammonite-repl

For more information — see Ammonite.io

Get the Start Script

I prepared a directory, where you find everything that you need to follow this Blog:

Configure the Tester

Open testRunner.sc. The only thing you need to adjust is the config Paths. This is a comma separated list with Paths where you have your DMN Tester Configs.

If you follow this example you do not need to change anything!

Here is the example if you will have your Configs in dmnConfigs:

#!/usr/bin/env amm

// repo for DMN Tester
interp.repositories() ++= Seq( coursierapi.MavenRepository.of("https://dl.bintray.com/pme123/maven"))

// this compiles the script in 2 parts (add first resolver and then runs the script)

@

import $ivy.`pme123::camunda-dmn-tester-server:0.6.0`
import pme123.camunda.dmn.tester.server.HttpServer

// add here your comma separated list with Paths you have your DMN Tester Configs
val configPaths = "/dmnConfigs"

sys.props.addOne("TESTER_CONFIG_PATHS", configPaths)

HttpServer.main(Array.empty[String])

Start the Server

In the Directory of the testRunner.sc, you can start now the Server:

$ amm testRunner.sc

Here the console:

nbszmbp013:demo mpa$ amm testRunner.sc 
Compiling /Users/mpa/dev/Github/pme123/camunda-dmn-tester/demo/testRunner.sc
Compiling /Users/mpa/dev/Github/pme123/camunda-dmn-tester/demo/testRunner.sc #2
Server starting at Port 8883
[ioapp-compute-0] INFO org.http4s.blaze.channel.nio1.NIO1SocketServerGroup - Service bound to address /0:0:0:0:0:0:0:0:8883
[ioapp-compute-0] INFO org.http4s.server.blaze.BlazeServerBuilder -
_ _ _ _ _
| |_| |_| |_ _ __| | | ___
| ' \ _| _| '_ \_ _(_-<
|_||_\__|\__| .__/ |_|/__/
|_|
[ioapp-compute-0] INFO org.http4s.server.blaze.BlazeServerBuilder - http4s v0.21.12 on blaze v0.14.14 started at http://[::]:8883/

Now open http://localhost:8883 in your Browser.

You should see something like this:

Docker Setup

You can run a Docker Container or use the image with Docker-Compose.

Docker-Compose:

You find a docker-compose.yml in the demo directory.

camunda-dmn-tester:
image: pame/camunda-dmn-tester:latest
environment:
TESTER_CONFIG_PATHS: "/dmnConfigs"
volumes:
- ./dmns:/opt/docker/dmns
- ./dmnConfigs:/opt/docker/dmnConfigs
ports:
- "8883:8883"

The volumes and the environment is analog as described above.

In the demo directory run:

docker-compose -f docker-compose.yml --project-directory . -p camunda-dmn-tester up

Now open http://localhost:8883 in your Browser.

Docker Run:

Or just start a Docker Container with the following command:

docker run \
--name camunda-dmn-tester \
--rm \
-it \
-e TESTER_CONFIG_PATHS="/dmnConfigs" \
-v $(pwd)/dmns:/opt/docker/dmns \
-v $(pwd)/dmnConfigs:/opt/docker/dmnConfigs \
-p 8883:8883 \
pame/camunda-dmn-tester

Ok, line by line:

Camunda Modeler

To edit the DMNs I use the Camunda Modeler.

Let’s Test DMN Tables

We take the DMN from the Decision Requirements Graph (DRG) Example.

So we start with the following file structure:

|-testRunner.sc
|-dmns
|-dinnerDecisions.dmn
|-dmnConfigs

As we have only specified one Path (/dmnConfigs), there is nothing to do here.

If you get an Exception here, make sure you have created the Path (/dmnConfigs).

Hit the blue Button and you get a form, where you can configure the DMN Table.

We start with the ‘dish’ table:

That’s it — hit the Save Button!

To run the configuration select it and Run it.

This shows you that this DMN is correct:

Each Test Case is one row, that gives you the following information:

As everything worked — there is not much to do. Let’s add some Bugs😇.

Invalid Input

With these warnings you find the typo on first sight.

Here we missed the boundary case. Together with the valid tests for Spring we see that we used < 4 instead of ≤ 4.

Ok here now the test — do you see the problem😀:

Solution: we have 5 not included with (5..8] — we need [5..8].

Invalid Output

This one is a bit trickier, but you will figure out that the Apostrophes (“) are missing.

Invalid Match Results

If you use the Hit Policy UNIQUE the DMN Tester can help you even better.

You see that with a guest count of 5 we have 2 matches. The same result with the Hit Policy FIRST:

So hard to say if this is what you wanted.

Test Case Creation

As you can imagine, the number of Test Cases can be overwhelming. So what we can do is to mark every Result that is correct and persist it to the DMN Configuration.

Just check the validated (correct) Rows and hit the blue button:

Running the Tests again gives you now the following result:

The DMN Row and the outputs are now checked if they haven’t changed. So if we change our DMN that changes the Result we see this right away:

Test Driven Development

We covered so far more or less the Use Cases where the Process Responsible gets the DMN and checks if it is valid.

In the beginning I even made this statement:

To convince business people to start working Test-Driven, looks to me not very promising.

So let’s see how the Business People can even use the DMN Tester to develop their DMNs in a Test Driven way.

Our DMN is empty of course. We define the first Rule in the DMN Config Editor:

As expected there is no Rule yet:

After adding the Rule:

The Rule matches and we can go to the next Rule.

Voilà — we can develop our DMNs step by step.

Open Issues

Conclusion

The DMN Table Tester should give you:

Try it out and let me know what you think!

Update 22.2.2021: I added a Part 2 that show how to create Regression Tests with the DMN Tester.

Working for finnova.com in the Banking business. Prefer to work with Scala / ScalaJS.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store