使用JUnit进行Drools测试

12

如何用JUnit测试Drools规则的最佳实践?

目前为止,我们使用dbunit和junit来测试规则。我们有一些样例数据被放入hsqldb中。在项目结尾时,很难创建一个好的测试数据输入,以测试特定的规则而不触发其他规则。

准确的问题是如何在JUnit中限制测试范围,只测试一个或多个特定的规则?

5个回答

7

个人而言,我使用单元测试来测试隔离的规则。我认为这并没有什么太大的问题,只要你不会因为隔离的规则有效就产生虚假的安全感,认为你的知识库能够正常工作。测试整个知识库更加重要。

您可以使用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-can.html

这篇文章是关于IT技术的,讲述了一些规则在实际使用中可能会出现的问题,以及如何解决这些问题。作者提供了一些有用的提示和技巧来帮助读者更好地理解和应用这些规则。如果您对IT技术感兴趣,可以点击上面的链接查看完整的文章。

5
不要试图将规则执行限制为测试中的单个规则。与OO类不同,单个规则并不独立于其他规则,因此在测试单个类时使用单元测试的方式来孤立地测试规则是没有意义的。换句话说,要测试单个规则,请测试它与其他规则组合后的正确效果。
相反,使用少量数据在所有规则上运行测试,即在规则会话中使用最少数量的事实,并测试结果以及可能触发了特定规则。实际上,结果与您所想的并没有太大不同,因为最小的测试数据集可能只会激活一两个规则。
至于样本数据,我更喜欢使用静态数据并为每个测试定义最小的测试数据。有各种各样的方法可以做到这一点,但在Java中以编程方式创建事实对象可能已经足够好了。

是的,我知道规则执行的工作原理。这是我们现在所做的方式。我的问题是这种方法很难制作足够和适当的测试数据。因为我们不限制可运行的规则,任何其他规则都可以运行并更改最终结果。因此,很难预测断言的最终结果。这就是为什么我认为单独测试规则会更好的原因。 - Hubidubi
我想我想说的是,事实上,“任何其他规则都可以运行并改变最终结果”正是为什么孤立地测试一个规则意义较小的原因。 - Peter Hilton

5

我创建了一个简单的库,帮助编写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/web/20140612080518/http://maciejwalkowiak.pl/blog/2013/11/24/jboss-drools-unit-testing-with-junit-drools/


(本段内容涉及IT技术,具体翻译可能因语境略有不同而有所不同。)

找不到 GitHub URL,Maven 中缺少 pl.maciejwalkowiak:junit-drools:jar:1.0。 - Yousef Al Kahky
@YousefAlKahky的项目已被存档,您可以在https://github.com/maciejwalkowiak/junit-drools上查看。 - Maciej Walkowiak

4
使用DBUnit进行单元测试并不是很理想,而使用DBUnit进行集成测试则更好。原因如下: - 单元测试应该快速。 -- 使用DBUnit恢复数据库需要时间,通常需要30秒。 -- 实际应用程序中有许多非空列,因此为了测试一个特定功能所需的数据,往往会占用数据库表的一半以上。 - 单元测试应该独立。 -- 为了保持测试独立性,每次测试都要还原DBUnit数据库,但这种方法有缺点: --- 运行所有测试需要数小时(特别是随着应用程序增长),因此没有人运行它们,因此它们经常失败,因此被禁用,因此没有测试,因此您的应用程序充满错误。 --- 每个单元测试都创建一半的数据库需要大量创建工作和维护工作,容易变得无效(关于验证方面,数据库模式不支持,请参见Hibernate Validator),而且通常不能很好地代表现实。 相反,使用DBunit编写集成测试: - 一个DBunit,对所有测试都相同。仅加载一次(即使运行500个测试)。 -- 将每个测试包装在事务中,并在每个测试后回滚数据库。大多数方法都使用传播required。仅当需要新的传播时才将测试数据设置为dirty(以便在下一个测试中重置它)。 - 用边缘情况填充数据库。不要添加比测试业务规则所需的更多常见情况,因此通常只有2个常见情况(以便能够进行“一对多”测试)。 - 编写具有未来保障的测试: -- 不要测试激活规则的数量或插入事实的数量。 -- 相反,请测试结果中是否存在某个特定插入的事实。将结果过滤为某个属性设置为X(与该属性的常见值不同),并测试具有该属性设置为X的插入事实的数量。

嗨,Geoffrey,你能否提供一些关于DBUnit的文档/链接,并给出一个通用的实现DBUnit与Drools结合的方法? - Shashank Bodkhe

0

单元测试是指对最小的代码片段进行测试,以定义规范并测试所有可能的用例。而集成测试的目标不是所有可能的用例,而是多个一起工作的单元的集成。同样的方法也适用于规则。按业务含义和目的将规则分离。最简单的“测试单元”可以是具有单个或高内聚性规则集合的文件,以及其所需的内容(如果有),例如常见的DSL定义文件和决策表。对于集成测试,您可以选择系统中有意义的子集或所有规则。

采用这种方法,您将拥有许多隔离的单元测试和少量集成测试,其中包含有限数量的公共输入数据,以重现和测试常见情况。添加新规则不会影响大多数单元测试,但会影响少数集成测试,并反映新规则如何影响公共数据流。

考虑使用适合此方法的JUnit测试库testing library


看起来是个不错的答案,但在Drools 7.5中并不适用,因为(正如maven repo所说):kie.internal - Drools和jBPM的内部API,在发布之间不具备向后兼容性。 :-( - Tihamer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接