Use your business data to your advantage with the help of Syncfusion’s new data science offerings. Discover how a custom big data solution can provide your company with valuable predictions about key market trends.

Testing your JBoss Drools Business Rules using Unit Testing

Packt Publishing

Capture, automate, and reuse your business processes in a clear English language that your computer can understand.

What is unit testing?

A good enterprise computer system should be built as if it was made of Lego bricks. Your rules are only a piece of the puzzle. You'll need to go back to the Lego box to get pieces that talk to the database, make web pages, talk to other systems that you may have in your company (or organization), and so on. Just as Lego bricks can be taken apart and put together in many different ways, the components in a well-designed system should be reusable in many different systems.

Before you use any of these components (or 'bricks') in your system, you will want to be sure that they work. For Lego bricks this is easy—you can just make sure that none of the studs are broken. For components this is a bit harder—often, you can neither see them, nor do you have any idea whether their inputs and outputs are correct. Unit testing makes sure that all of the component pieces of your application work, before you even assemble them.

You can unit test manually, but just like FIT requirements testing, you're going to 'forget' to do it sooner or later. Fortunately, there is a tool to automate your unit tests known as Junit (for Java; there are also versions for many other languages, such as .Net). Like Drools and FIT, Junit is open source. Therefore, we can use it on our project without much difficulty. Junit is integrated into the JBoss IDE and is also pretty much an industry standard, so it's easy to find more information on it. A good starting point is the project's home page at http://www.Junit.org.

The following points can help you to decide when to use unit testing, and when to use the other forms of testing that we talked about:

If you're most comfortable using Guvnor, then use the test scenarios within Guvnor. As you'll see shortly, they're very close to unit tests.

If the majority of your work involves detailing and signing off against the requirement documents, then you should consider using FIT for Rules.

If you're most comfortable using Java, or some other programming language, then you're probably using (J)unit tests already—and we can apply these unit tests to rule testing.

In reality, your testing is likely to be a mix of two or three of these options.

Why unit test?

An important point to note is that you've already carried out unit testing in the rules that we wrote earlier. OK, it was manual unit testing, but we still checked that our block of rules produced the outcome that we expected. All we're talking about here is automating the process.

Unit testing also has the advantage of documenting the code because it gives a working example of how to call the rules. It also makes your rules and code more reusable. You've just proved (in your unit test) that you can call your code on a standalone basis, which is an important first step for somebody else to be able to use it again in the future.

You do want your rules to be reused, don't you?

Unit testing the Chocolate Shipments sample

As luck would have it, our Chocolate Shipments example also contains a unit test. This is called DroolsUnitTest.java, and it can be found in the test/java/net/firstpartners/chap7 folder.

Running the Junit test is similar to running the samples. In the JBoss IDE Navigator or package explorer, we select DroolsUnitTest.java, right-click on it, and then select Run as | Junit test from the shortcut menu.

All being well, you should see some messages appear on the console. We're going to ignore the console messages; after all, we're meant to be automating our testing, not manually reading the console. The really interesting bit should appear in the IDE— the Junit test result, similar to the screenshot shown below. If everything is OK, we should see the green bar displayed—success!

We've run only one unit test, so the output is fairly simple. From top to bottom we have: the time it took to run the test; the number of errors and failures (both zero—we'll explain the difference shortly, but having none of them is a good thing), the green bar (success!), and a summary of the unit tests that we've just run (DroolsUnitTest).

If you were running this test prior to deploying to production, all you need to know is that the green bar means that everything is working as intended. It's a lot easier than inspecting the code line by line.

However, as this is the first time that we're using a unit test, we're going to step through the tests line by line. A lot of our Junit test is similar to MultipleRulesExample.java. For example, the unit test uses the same RuleRunner file to load and call the rules. In addition, the Junit test also has some automated checks (asserts) that give us the green bar when they pass, which we saw in the previous screenshot.

What just happened?

Probably the easiest way to understand what just happened is to walk through the contents of the DroolsUnitTest.java file. Our unit code starts with the usual package information. Even though it is in a separate folder, Java is fooled into using the same package.

package net.firstpartners.chap7;

In our imports section (list of other files that we need), we have a mix of our domain objects (the facts such as CustomerOrder) that we used earlier for holding information. We also have the logging tools. What is new is the imports of Assert (part of our automatic checking tool) and importing the junit test (the template for our unit test).

Earlier, our starting point was called main so that Java knew where we wanted it to start when we pressed the green Go button. This time, our start method is called testShippingRules and it's marked with a @Test flag so that we know it's an entry point. We can have multiple tests, each marked with @Test. The Junit framework will test each one in turn.

The rest of this code snippet, which involves setting up and calling the business rules via RuleRunner, is exactly the same as our previous 'calling the rule engine' samples.

In our previous example, once we called the rules, we printed the results out to the screen for manual inspection. This time things are different. We want to make this checking automatic. Hence, we have added following new lines in the final snippet, using assertXXX to check if the values that we get back from the rules are as expected:

// Check that the results are as we expectedassertEquals("No more bars should be left to ship", 0, candyBarOrder.getCurrentBalance());assertEquals("Our initial order balance should not be changed",2100, candyBarOrder.getInitialBalance());assertNotNull("Our list of shipments should contain a value",candyBarOrder.getShipments());assertTrue("We should have some Cusomter Shipments",candyBarOrder.getShipments().size() > 5);}}

In general, our assert checks follow the format: Assert( "message if the value is not as we expect" , valueWeExpected, valueWeGotWhenWeRanTheTest)

The first line (assertEquals) compares the number of candy bars that should still be left to ship after our rules have fired (should be 0)

The second line (assertEquals) ensures that the initial order is not changed by the rules, and remains at 2100

The next line (assertNotNull) ensures that the list of shipments that we made is not empty

The final line (assertTrue) checks that we have more than five shipments made to a customer

Is it best to have multiple tests or multiple asserts within a single test? It is possible to have multiple tests, such as someTest() methods (each marked with @Test), and/or multiple tests using assertXXX within a method. A combination of both is probably the best. Multiple asserts in one method are great when your test is difficult to set up, but the test will stop at the first assert that turns out to be false. This means you can solve the first error, but your test will then stop at the next assert that fails. Having these asserts in separate test methods shows you instantly how many problem(s) you have—at the price of having some duplicated setup code.

What if it goes wrong?

We were lucky that our tests worked the very first time. Unfortunately, this is almost impossible to achieve. For example, assume that we mistakenly wrote a rule that changed the initial balance.

assertEquals("Our initial order balance should not be changed",2100, candyBarOrder.getInitialBalance());

In this case, when we come to check, our test will fail. We will get a red bar in our unit tests, detailing what has gone wrong (similar to the screenshot below). The message in our assert (Our initial order balance should not be changed) and other details (such as line numbers) are provided to help us trace what is going wrong. You'll also notice that the Failures count is now 1.

Failures and errors

So what's the difference between failures and errors? Failures are things (such as the above assert) that we explicitly check for. Errors are the unexpected things that go wrong. Remember our NullPointerException from the previous section in FIT? That is, the problem that we face when something is empty that shouldn't be. That exception is shown as an error in Junit with a red bar (again), along with the details of the problem to help you fix it.It's simple—green is good and red is bad. But remember, it's always better to catch mistakes early.

Testing an entire package

Typically, you write a unit test at the same time as writing a set of rules to confirm that the functionality is 'done'.

After you're 'done', you (or one of your team) should run all of the tests in the project to make sure that your new work hasn't broken any of the rules or code that already existed. There are a couple of ways to automatically do this overnight (as part of a build control tool such as Cruise Control) as part of your build scripts, or you can run all of the tests from the JBoss IDE (akin to the 'run all scenarios in package' that we saw in Guvnor).

It's pretty easy to run all of your unit tests in one go. All you have to do is this:

From the toolbar (at the very top of the JBoss IDE) select Run.

In the dialog box that is dispalyed, selectJunit (near the lower-left of the screen) and then click on New launch configuration (the icon on the upper-left of the screen, as shown in the screenshot).

On the righthand side, fill in the following values:

Click on Apply (to save it, so that you don't have to go through all of the steps the next time), and then click on Run.

As before, the JBoss IDE will chug away for a couple of moments, and then the popup Junit screen will be displayed.

As before, if any of the multiple tests fail, you'll see a red bar, along with details of all of the items that went wrong. When all of your tests pass, you can be sure that your rules are of top quality?.

Alerts & Offers

Series & Level

We understand your time is important. Uniquely amongst the major publishers, we seek to develop and publish the broadest range of learning and information products on each technology. Every Packt product delivers a specific learning pathway, broadly defined by the Series type. This structured approach enables you to select the pathway which best suits your knowledge level, learning style and task objectives.

Learning

As a new user, these step-by-step tutorial guides will give you all the practical skills necessary to become competent and efficient.

Beginner's Guide

Friendly, informal tutorials that provide a practical introduction using examples, activities, and challenges.

Essentials

Fast paced, concentrated introductions showing the quickest way to put the tool to work in the real world.

Cookbook

A collection of practical self-contained recipes that all users of the technology will find useful for building more powerful and reliable systems.

Blueprints

Guides you through the most common types of project you'll encounter, giving you end-to-end guidance on how to build your specific solution quickly and reliably.

Mastering

Take your skills to the next level with advanced tutorials that will give you confidence to master the tool's most powerful features.

Starting

Accessible to readers adopting the topic, these titles get you into the tool or technology so that you can become an effective user.

Progressing

Building on core skills you already have, these titles share solutions and expertise so you become a highly productive power user.