Blog Posts BPMN DMN

Simplifying Drools Tests with AssertJ

Blog: Drools & jBPM Blog

Introduction

Creating clean, concise, and maintainable tests is crucial for any software project. In this post, we will discuss the ongoing refactoring process for Drools tests and illustrate how these techniques can benefit other projects. By leveraging the expressiveness of AssertJ assertions, we aim to enhance readability and conciseness, leading to more efficient and easily comprehensible tests.

The Original Code

The code used in this example comes from the drools project.

The test class is BackwardChainingTest and the test method is testQueryWithOr.

The code can be retrieved from here: BackwardChainingTest.java

In the original tests the block we are considering uses roughly 55 lines of code.

Let’s start by examining a snippet from the original code:

List list = new ArrayList();
Query Results results = ksession.getQueryResults("p", new Integer[]{2});
for (final QueryResultsRow result : results) {
    list.add((Integer) result.get("x"));
}
assertThat(list.size()).isEqualTo(1);
assertThat(list.get(0).intValue()).isEqualTo(2);

This code retrieves query results from a Drools knowledge session (ksession) and iterates through the results to add them to a list. It then asserts the list size and content. 

While this code works, it’s not as concise or expressive as it could be.

Let’s see how we can improve this code.

Step 1 – Use AssertJ assertions

The snippet presented before uses AssertJ assertions. We can improve the code by leveraging the assertions for collections of AssertJ.

List list = new ArrayList();
QueryResults results = ksession.getQueryResults("p", new Integer[]{2});
for (final QueryResultsRow result : results) {
    list.add((Integer) result.get("x"));
}

assertThat(list).hasSize(1); 
assertThat(list).contains(2);

These assertions are now clearer and simpler, but they can be simplified more. The first assertion states that list contains only one element, and the second assertion states that list contains exactly the element 2. So we can rewrite this snippet as follow:

List list = new ArrayList();
QueryResults results = ksession.getQueryResults("p", new Integer[]{2});
for (final QueryResultsRow result : results) {
    list.add((Integer) result.get("x"));
}
assertThat(list).containsExactly(2); 

Step 2 – Create collections on the fly using extracting

This is already simpler and better, however there is still the rather ugly code represented by the creation of the list collection. We are creating the list collection just for the assertion.

Fortunately AssertJ has a very powerful mechanism to create collections on the fly and use them for assertions, named extracting. With extracting it is possible to take a collection, extract one or more properties from all the elements of the collections and then use the resulting collection to perform assertions.

Here is the code using extracting:

QueryResults results = ksession.getQueryResults("p", new Integer[]{2});
assertThat(results).extracting(r -> r.get("x")).containsExactly(2); 

We have now removed the code for initializing the variable list, and we are down only two lines.

Step 3 – Inline variable in a single assertion

Looking at the getQueryResult method of the session, it is clear that it already takes a vararg argument, so it is not necessary to use an array.

QueryResults results = ksession.getQueryResults("p", 2);
assertThat(results).extracting(r -> r.get("x")).containsExactly(2);

As an optional step, we can remove the array and inline the result variable, obtaining a much more compacted version of our original assertion:

assertThat(ksession.getQueryResults("p",2)).extracting(r -> r.get("x")).containsExactly(2); 

This is marked optional since some people prefer to keep intermediate variables on separate lines for debugging purposes.

Step 4 – The final result

Repeating the process for all the original 55 lines of codes in the test produces the final result:

assertThat(ksession.getQueryResults("p", 0)).extracting(r -> r.get("x")).isEmpty();
assertThat(ksession.getQueryResults("p", 1)).extracting(r -> r.get("x")).containsExactly(1);
assertThat(ksession.getQueryResults("p", 2)).extracting(r -> r.get("x")).containsExactly(2);
assertThat(ksession.getQueryResults("p", 3)).extracting(r -> r.get("x")).containsExactly(3);
assertThat(ksession.getQueryResults("p", 4)).extracting(r -> r.get("x")).isEmpty();
assertThat(ksession.getQueryResults("p", 5)).extracting(r -> r.get("x")).isEmpty();
assertThat(ksession.getQueryResults("p", 6)).extracting(r -> r.get("x")).containsExactly(6, 6);

This uses only 7 lines of codes and it is much more clear than the original version.

Conclusions

In our view the new version of the code is better for several reasons:

We hope you can reuse part or all of these patterns to improve the tests of other projects. 

The post Simplifying Drools Tests with AssertJ appeared first on KIE Community.

Leave a Comment

Get the BPI Web Feed

Using the HTML code below, you can display this Business Process Incubator page content with the current filter and sorting inside your web site for FREE.

Copy/Paste this code in your website html code:

<iframe src="https://www.businessprocessincubator.com/content/simplifying-drools-tests-with-assertj/?feed=html" frameborder="0" scrolling="auto" width="100%" height="700">

Customizing your BPI Web Feed

You can click on the Get the BPI Web Feed link on any of our page to create the best possible feed for your site. Here are a few tips to customize your BPI Web Feed.

Customizing the Content Filter
On any page, you can add filter criteria using the MORE FILTERS interface:

Customizing the Content Filter

Customizing the Content Sorting
Clicking on the sorting options will also change the way your BPI Web Feed will be ordered on your site:

Get the BPI Web Feed

Some integration examples

BPMN.org

XPDL.org

×