使用 junit 进行 Drools 测试

发布于 2024-09-25 23:58:22 字数 190 浏览 8 评论 0原文

使用 junit 测试 drools 规则的最佳实践是什么?

到目前为止,我们使用 junit 和 dbunit 来测试规则。我们有放入 hsqldb 的示例数据。我们有几个规则包,到项目结束时,很难做出良好的测试输入来测试某些规则而不触发其他规则。

所以确切的问题是,如何将 junit 中的测试限制为一个或多个特定规则来进行测试?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

淡墨 2024-10-02 23:58:22

我个人使用单元测试来测试孤立的规则。我认为这没有什么太大的问题,只要你不陷入一种错误的安全感,即你的知识库正在发挥作用,因为孤立的规则正在发挥作用。测试整个知识库更为重要。

您可以使用 AgendaFilter 编写隔离测试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.

代码来源: http:// /blog.athico.com/2007/07/my-rules-dont-work-as-expected-what-c​​an.html

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

酒解孤独 2024-10-02 23:58:22

不要尝试将规则执行限制为测试的单个规则。与 OO 类不同,单个规则并不独立于其他规则,因此像使用单元测试测试单个类一样单独测试规则是没有意义的。换句话说,要测试单个规则,请测试它与其他规则组合是否具有正确的效果。

相反,使用少量数据对所有规则运行测试,即在规则会话中使用最少数量的事实,并测试结果以及可能是否触发了特定规则。结果实际上与您的想法没有太大不同,因为最小的测试数据集可能只激活一两个规则。

至于样本数据,我更喜欢使用静态数据并为每个测试定义最少的测试数据。有多种方法可以做到这一点,但在 Java 中以编程方式创建事实对象可能就足够了。

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.

小红帽 2024-10-02 23:58:22

我创建了一个简单的库,可以帮助为 Drools 编写单元测试。其中一个功能正是您所需要的:声明您想要用于单元测试的特定 drl 文件:

@RunWith(DroolsJUnitRunner.class)
@DroolsFiles(value = "helloworld.drl", location = "/drl/")
public class AppTest {

    @DroolsSession
    StatefulSession session;

    @Test
    public void should_set_discount() {
        Purchase purchase = new Purchase(new Customer(17));

        session.insert(purchase);
        session.fireAllRules();

        assertTrue(purchase.getTicket().hasDiscount());
    }
}

有关更多详细信息,请查看博客文章:https://web.archive.org/网页/20140612080518/http://maciejwalkowiak.pl/blog/2013/11/24/jboss-drools-unit-testing-with-junit-drools/

I created simple library that helps to write unit tests for Drools. One of the features is exactly what you need: declare particular drl files you want to use for your unit test:

@RunWith(DroolsJUnitRunner.class)
@DroolsFiles(value = "helloworld.drl", location = "/drl/")
public class AppTest {

    @DroolsSession
    StatefulSession session;

    @Test
    public void should_set_discount() {
        Purchase purchase = new Purchase(new Customer(17));

        session.insert(purchase);
        session.fireAllRules();

        assertTrue(purchase.getTicket().hasDiscount());
    }
}

For more details have a look on blog post: https://web.archive.org/web/20140612080518/http://maciejwalkowiak.pl/blog/2013/11/24/jboss-drools-unit-testing-with-junit-drools/

幼儿园老大 2024-10-02 23:58:22

使用 DBUnit 进行单元测试实际上并不起作用。与 DBUnit 的集成测试可以。原因如下:
- 单元测试应该很快。
-- DBUnit 数据库恢复速度很慢。轻松花30秒。
-- 实际应用程序有许多非空列。因此,针对单个功能隔离的数据仍然可以轻松使用数据库的一半表。
- 单元测试应该被隔离。
-- 为每个测试恢复 dbunit 数据库以保持它们隔离有缺点:
--- 运行所有测试需要几个小时(尤其是随着应用程序的增长),所以没有人运行它们,所以它们不断地中断,所以它们被禁用,所以没有测试,所以你的应用程序充满了错误。
--- 为每个单元测试创​​建半个数据库是大量的创建工作,大量的维护工作,很容易变得无效(关于数据库模式不支持的验证,请参阅 Hibernate Validator)并且通常效果不好代表现实的工作。

相反,使用 DBunit 编写集成测试:
- 一个 DBunit,所有测试都相同。仅加载一次(即使您运行 500 次测试)。
-- 将每个测试包装在一个事务中,并在每次测试后回滚数据库。无论如何,大多数方法都使用所需的传播。仅当传播为 require_new 时,才将测试数据设置为脏(如果有下一个测试,则在下一个测试中重置它)。
- 用极端情况填充该数据库。添加的常见案例不要超出测试业务规则所需的数量,因此通常只有 2 个常见案例(以便能够测试“一对多”)。
- 编写面向未来的测试:
-- 不要测试激活规则的数量或插入事实的数量。
-- 相反,测试结果中是否存在某个插入的事实。对设置为 X 的某个属性(不同于该属性的公共值)过滤结果,并测试该属性设置为 X 的插入事实的数量。

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.

面如桃花 2024-10-02 23:58:22

单元测试是关于采用最少的代码并测试定义规范的所有可能的用例。通过集成测试,您的目标不是所有可能的用例,而是集成多个协同工作的单元。对规则也做同样的事情。按业务含义和目的分隔规则。最简单的“测试单元”可以是带有单个或 高内聚规则集以及其工作所需的条件(如果有),例如通用 dsl 定义文件和决策表。对于集成测试,您可以采用系统的有意义的子集或所有规则。

通过这种方法,您将进行许多独立的单元测试和少量的集成测试,并使用有限数量的公共输入数据来重现和测试常见场景。添加新规则不会影响大多数单元测试,但会影响很少的集成测试,并将反映新规则如何影响公共数据流。

考虑适合这种方法的 JUnit 测试库

Unit test is about taking minimum piece of code and test all possible usecases defining specification. With integration tests your goal is not all possible usecases but integration of several units that work together. Do the same with rules. Segregate rules by business meaning and purpose. Simplest 'unit under the test' could be file with single or high cohension set of rules and what is required for it to work (if any), like common dsl definition file and decision table. For integration test you could take meaningful subset or all rules of the system.

With this approach you'll have many isolated unit tests and few integration tests with limited amount of common input data to reproduce and test common scenarios. Adding new rules will not impact most of unit tests but few integration tests and will reflect how new rules impact common data flow.

Consider JUnit testing library that could be suitable for this approach

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文