Testing your JBoss Drools Business Rules using Unit Testing

Exclusive offer: get 50% off this eBook here
JBoss Drools Business Rules

JBoss Drools Business Rules — Save 50%

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

$29.99    $15.00
by Paul Browne | April 2009 | Java Open Source

In the previous article we've seen how to test our rules using Guvnor, as well as using FIT for rule testing against requirements documents. This article by Paul Browne, shows how to test your rules further. It shows how to unit test the rules by using Junit. Unit testing 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.

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!

JBoss Drools Business Rules

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.

JBoss Drools Business Rules Capture, automate, and reuse your business processes in a clear English language that your computer can understand.
Published: April 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

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).

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import net.firstpartners.chap6.domain.CustomerOrder;
import net.firstpartners.chap6.domain.OoompaLoompaDate;

import net.firstpartners.drools.RuleRunner;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.junit.Test;

The start of the main part of the file may be renamed to DroolsUnitTest, but what it does is the same. The rules are still read from exactly the same file as before.

public class DroolsUnitTest {
private static Log log = LogFactory.getLog(DroolsUnitTest.class);

private static final String NEXT_AVAILABLE_SHIPMENT_DATE =
"nextAvailableShipmentDate";

private static final String[] RULES_FILES = new String[] { "src/
main/java/net/firstpartners/chap6/shipping-rules.drl" };

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.

@Test
public void testShippingRules() throws Exception {
// Initial order
CustomerOrder candyBarOrder = new CustomerOrder(2000);
HashMap<String, Object> startDate = new HashMap<String, Object>();
startDate.put(NEXT_AVAILABLE_SHIPMENT_DATE, new
OoompaLoompaDate(2009, 02, 03));
// Holidays
OoompaLoompaDate holiday2 = new OoompaLoompaDate(2009, 2, 10);
OoompaLoompaDate holiday1 = new OoompaLoompaDate(2009, 3, 17);
// Call the rule engine
Object[] facts = new Object[3];
facts[0] = candyBarOrder;
facts[1] = holiday1;
facts[2] = holiday2;
// A lot of the running rules uses the same code. The RuleRunner (code
// in this project)
// keeps this code in one place. It needs to know
// - the name(s) of the files containing our rules
// - the fact object(s) containing the information to be passed in and
// out of our rules
// - a list of global values
new RuleRunner().runRules(RULES_FILES, facts, startDate);

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 expected
assertEquals(
"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.

JBoss Drools Business Rules

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:

  1. From the toolbar (at the very top of the JBoss IDE) select Run.
  2. 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).

    JBoss Drools Business Rules

  3. On the righthand side, fill in the following values:

    JBoss Drools Business Rules

  4. 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?.

Summary

Thus in this two part series on testing we have seen :

 

If you have read this article you may be interested to view :

 

JBoss Drools Business Rules Capture, automate, and reuse your business processes in a clear English language that your computer can understand.
Published: April 2009
eBook Price: $29.99
Book Price: $49.99
See more
Select your format and quantity:

About the Author :


Paul Browne

Paul Browne's first job was selling computers in France and things went steadily downhill from there. He spent millons on behalf of a UK telephone company's procurement department and implemented direct marketing for a well-known Texan computer maker before joining the IT department of a company that builds bright red tractors and other seriously cool machines.

Paul then embraced his techie side (he was writing games in machine code from the age of 11) and started a consultancy that used IT to solve business problems for companies in the financial and public sectors in Ireland, UK , Belgium, and New Zealand. Eight years later, he now works with an Irish government agency that helps similar software companies to grow past their initial teething pains.

More formally, Paul has a bachelor's degree in Business and French from the University of Ulster, a master's degree in Advanced Software from UCD Dublin, a post-grad qualification in Procurement from the Chartered Institute of Procurement and Supply (UK), and will someday complete his ACCA financial exams.

Paul can be found on LinkedIn at http://www.linkedin.com/in/paulbrowne , and via the Red Piranha (Business knowledge) project at http://code.google.com/p/red-piranha/ .

Books From Packt

JBoss Portal Server Development
JBoss Portal Server Development

Learning jQuery 1.3
Learning jQuery 1.3

DWR Java AJAX Applications
DWR Java AJAX Applications

JBoss Tools 3 Developers Guide
JBoss Tools 3 Developers Guide

Java EE 5 Development with NetBeans 6
Java EE 5 Development with NetBeans 6

Spring 2.5 Aspect Oriented Programming
Spring 2.5 Aspect Oriented Programming

Drupal 6 Social Networking
Drupal 6 Social Networking

WordPress Plugin Development: Beginner's Guide
WordPress Plugin Development: Beginner's Guide

No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
p
c
K
1
f
D
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software