views:

31

answers:

3

Hi

What is the best practice to test drools rules with junit?

Until now we used junit with dbunit to test rules. We had sample data that was put to hsqldb. We had couple of rule packages and by the end of the project it is very hard to make a good test input to test certain rules and not fire others.

So the exact question is that how can I limit tests in junit to one or more certain rule(s) for testing?

Thanks for help,

Hubidubi

+1  A: 

Do not attempt to limit rule execution to a single rule for a test. Unlike OO classes, single rules are not independent of other rules, so it does not make sense to test a rule in isolation in the same way that you would test a single class using a unit test. In other words, to test a single rule, test that it has the right effect in combination with the other rules.

Instead, run tests with a small amount of data on all of your rules, i.e. with a minimal number of facts in the rule session, and test the results and perhaps that a particular rule was fired. The result is not actually that much different from what you have in mind, because a minimal set of test data might only activate one or two rules.

As for the sample data, I prefer to use static data and define minimal test data for each test. There are various ways of doing this, but programmatically creating fact objects in Java might be good enough.

Peter Hilton
yes I know how rule execution works. This is the way we do it now. My problem is with this approach that it is very hard to make enough and appropriate test data. Because we don't limit the runnable rules, any other rules can run and change the final result. So it's hard to predict the final result for asserts. That was the reason why I thought that it would be better to test rules izolated.
Hubidubi
I guess I was trying to say that the fact that 'any other rules can run and change the final result' is exactly why testing a rule in isolation is less meaningful.
Peter Hilton
A: 

A unit test with DBUnit doesn't really work. An integration test with DBUnit does. Here's why: - A unit test should be fast. -- A DBUnit database restore is slow. Takes 30 seconds easily. -- A real-world application has many not null columns. So data, isolated for a single feature, still easily uses half the tables of the database. - A unit test should be isolated. -- Restoring the dbunit database for every test to keep them isolated has drawbacks: --- Running all tests takes hours (especially as the application grows), so no one runs them, so they constantly break, so they are disabled, so there is no testing, so you application is full of bugs. --- Creating half a database for every unit test is a lot of creation work, a lot of maintenance work, can easily become invalid (with regards to validation which database schema's don't support, see Hibernate Validator) and ussually does a bad job of representing reality.

Instead, write integration tests with DBunit: - One DBunit, the same for all tests. Load it only once (even if you run 500 tests). -- Wrap each test in a transaction and rollback the database after every test. Most methods use propagation required anyway. Set the testdata dirty only (to reset it in the next test if there is a next test) only when propagation is requires_new. - Fill that database with corner cases. Don't add more common cases than are strictly needed to test your business rules, so ussually only 2 common cases (to be able to test "one to many"). - Write future-proof tests: -- Don't test the number of activated rules or the number of inserted facts. -- Instead, test if a certain inserted fact is present in the result. Filter the result on a certain property set to X (different from the common value of that property) and test the number of inserted facts with that property set to X.

+1  A: 

Personally I use unit tests to test isolated rules. I don't think there is anything too wrong with it, as long as you don't fall into a false sense of security that your knowledge base is working because isolated rules are working. Testing the entire knowledge base is more important.

You can write the isolating tests with AgendaFilter and StatelessSession

StatelessSession session = ruleBase.newStatelessSesssion();

session.setAgendaFilter( new RuleNameMatches("<regexp to your rule name here>") );

List data = new ArrayList();
... // create your test data here (probably built from some external file)

StatelessSessionResult result == session.executeWithResults( data );

// check your results here.

Code source: http://blog.athico.com/2007/07/my-rules-dont-work-as-expected-what-can.html

Toni Rikkola