目录
2.2.4.1 地址测试类结果(AddressDroolsTests)
2.2.4.2 订单积分规则测试类结果(OrderDroolsTests)
2.2.4.3 积分规则生成及积分测试类结果(DroolsTests)
一、需求说明与测试要点
1.1 需求说明
模拟消费赠送积需求,具体需求点如下:
用户下单原价金额:
- 100元以下, 不加分
- 100-500元加100分
- 500-1000元加500分
- 1000 以上元加1000分
1.2 测试内容及要点
测试要点:
- 检查测试地址是否正确
- 模拟用户下单金额,测试规则积分计算
二、需求实现
2.1 创建工程
2.1.1 引入maven依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/>
</parent>
<groupId>com.ningzhaosheng.drools</groupId>
<artifactId>drools-test</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.31</version>
</dependency>
<dependency>
<groupId>org.kie</groupId>
<artifactId>kie-spring</artifactId>
<version>7.74.1.Final</version>
<exclusions>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
</project>
2.1.2 规则引擎自动配置类
主要是实现规则文件加载和kie核心类装载、配置。
package com.ningzhaosheng.drools.config;
import org.kie.api.KieBase;
import org.kie.api.KieServices;
import org.kie.api.builder.KieBuilder;
import org.kie.api.builder.KieFileSystem;
import org.kie.api.builder.KieRepository;
import org.kie.api.runtime.KieContainer;
import org.kie.internal.io.ResourceFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import java.io.IOException;
/**
* @author ningzhaosheng
* @date 2024/1/17 17:40:41
* @description 规则引擎自动配置类
*/
@Configuration
public class DroolsAutoConfiguration {
private static final String RULES_PATH = "rules/";
@Bean
@ConditionalOnMissingBean(KieServices.class)
public KieServices getKieServices() {
return KieServices.Factory.get();
}
@Bean
@ConditionalOnMissingBean(KieFileSystem.class)
public KieFileSystem kieFileSystem() throws IOException {
KieFileSystem kieFileSystem = getKieServices().newKieFileSystem();
for (Resource file : getRuleFiles()) {
kieFileSystem.write(ResourceFactory.newClassPathResource(RULES_PATH + file.getFilename(), "UTF-8"));
}
return kieFileSystem;
}
private Resource[] getRuleFiles() throws IOException {
ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
return resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "**/*.*");
}
@Bean
@ConditionalOnMissingBean(KieContainer.class)
public KieContainer kieContainer() throws IOException {
final KieRepository kieRepository = getKieServices().getRepository();
kieRepository.addKieModule(() -> kieRepository.getDefaultReleaseId());
KieBuilder kieBuilder = getKieServices().newKieBuilder(kieFileSystem());
kieBuilder.buildAll();
KieContainer kieContainer = getKieServices().newKieContainer(kieRepository.getDefaultReleaseId());
return kieContainer;
}
@Bean
@ConditionalOnMissingBean(KieBase.class)
public KieBase kieBase() throws IOException {
return kieContainer().getKieBase();
}
}
2.1.3 SpringBoot 启动类
package com.ningzhaosheng.drools;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author ningzhaosheng
* @date 2024/1/17 17:42:56
* @description SpringBoot 启动类
*/
@SpringBootApplication
public class DroolsApplication {
public static void main(String[] args) {
SpringApplication.run(DroolsApplication.class, args);
System.out.println("启动成功");
}
}
2.1.4 SpringBoot 测试启动类
package com.ningzhaosheng.drools;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author ningzhaosheng
* @date 2024/1/17 17:15:44
* @description 启动测试
*/
@SpringBootTest
public class DroolsApplicationTests {
@Test
void contextLoads() {
}
}
2.2 业务需求实现
2.2.1 创建实体对象
2.2.1.1 创建用户实体
package com.ningzhaosheng.drools.integral.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:04:07
* @description 用户实体
*/
@Data
@Accessors(chain = true)
public class User {
// 用户名
private String name;
// 等级
private int level;
}
2.2.1.2 创建地址实体
package com.ningzhaosheng.drools.integral.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:05:27
* @description 地址实体
*/
@Data
@Accessors(chain = true)
public class Address {
private String postcode;
private String street;
}
2.2.1.3 地址检查状态实体
package com.ningzhaosheng.drools.integral.entity;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:06:15
* @description 地址检查状态实体
*/
@Data
@Accessors(chain = true)
public class AddressCheckResult {
private boolean postCodeResult = false;
}
2.2.1.4 订单实体
package com.ningzhaosheng.drools.integral.entity;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:02:41
* @description 订单实体
*/
@Data
@Accessors(chain = true)
public class Order {
/**
* 订单原价金额
*/
private int price;
/**
*下单人
*/
private User user;
/**
*积分
*/
private int score;
/**
* 下单日期
*/
private Date bookingDate;
}
2.2.2 创建规则文件
2.2.2.1 创建地址检查规则文件
在/resources/rules下创建规则文件address.drl,具体内容如下:
/*区域/战区 省市区的规则*/
package rules
import com.ningzhaosheng.drools.integral.entity.Address
import com.ningzhaosheng.drools.integral.entity.AddressCheckResult;
/*
地址检查规则
*/
rule "Postcode should be filled with exactly 5 numbers"
when
address : Address(postcode != null, postcode matches "([0-9]{5})")
checkResult : AddressCheckResult();
then
checkResult.setPostCodeResult(true);
System.out.println("规则中打印日志:校验通过1!");
end
rule "TEST"
when
address : Address(street != null, street=="测试")
checkResult : AddressCheckResult();
then
checkResult.setPostCodeResult(true);
System.out.println("规则中打印日志:校验通过2!");
end
2.2.2.2 创建订单积分规则文件
在/resources/rules下创建规则文件point-rules.drl,具体内容如下:
package rules
import com.ningzhaosheng.drools.integral.entity.Order
import com.ningzhaosheng.drools.integral.entity.User
/*
积分规则
*/
rule "zero"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price <= 100)
then
$order.setScore(0);
update($order);
end
rule "add100"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 100 && price <= 500)
// and $user : User(level>3)
then
System.out.println($order.getUser());
$order.setScore(100);
update($order);
end
rule "add500"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 500 && price <= 1000)
then
$order.setScore(500);
update($order);
end
rule "add1000"
no-loop true
lock-on-active true
salience 1
when
$order : Order(price > 1000)
then
$order.setScore(1000);
update($order);
end
2.2.3 编写测试类
2.2.3.1 编写地址测试类
package com.ningzhaosheng.drools.integral.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.integral.entity.Address;
import com.ningzhaosheng.drools.integral.entity.AddressCheckResult;
import org.junit.jupiter.api.Test;
import org.kie.api.KieBase;
import org.kie.api.runtime.KieSession;
import javax.annotation.Resource;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:16:19
* @description 地址测试类
* 需求
* 模拟生成地址数据
* 触发地址规则校验
*/
public class AddressDroolsTests extends DroolsApplicationTests {
@Resource
public KieBase kieBase;
@Test
public void droolsOrderTest() {
KieSession kieSession = kieBase.newKieSession();
Address address = new Address();
address.setPostcode(generateRandom(5));
address.setStreet("测试1");
AddressCheckResult result = new AddressCheckResult();
kieSession.insert(address);
kieSession.insert(result);
int ruleFiredCount = kieSession.fireAllRules();
System.out.println("触发了" + ruleFiredCount + "条规则");
if (result.isPostCodeResult()) {
System.out.println("规则校验通过");
}
}
/**
* 生成随机数
*
* @param num
* @return
*/
public String generateRandom(int num) {
String chars = "0123456789";
StringBuffer number = new StringBuffer();
for (int i = 0; i < num; i++) {
int rand = (int) (Math.random() * 10);
number = number.append(chars.charAt(rand));
}
return number.toString();
}
}
2.2.3.2 编写订单积分规则测试类
package com.ningzhaosheng.drools.integral.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.integral.entity.Order;
import com.ningzhaosheng.drools.integral.entity.User;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.junit.jupiter.api.Test;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:23:41
* @description 测试订单积分规则
* 计算额外积分金额 规则如下: 订单原价金额
* 100以下, 不加分
* 100-500 加100分
* 500-1000 加500分
* 1000 以上 加1000分
*/
public class OrderDroolsTests extends DroolsApplicationTests {
public KieSession getKieSession() {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("rules/point-rules.drl"), ResourceType.DRL);
//BUILD RULEBASE
InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addPackages(kbuilder.getKnowledgePackages());
//NEW WORKING MEMORY
final KieSession session = kbase.newKieSession();
return session;
}
/**
* if -else
*
* @throws Exception
*/
/*@Test
public void Test() throws Exception {
List<Order> orderList = getInitData();
for (Order order : orderList) {
if (order.getPrice() <= 100) {
order.setScore(0);
addScore(order);
} else if (order.getPrice() > 100 && order.getPrice() <= 500) {
order.setScore(100);
addScore(order);
} else if (order.getPrice() > 500 && order.getPrice() <= 1000) {
order.setScore(500);
addScore(order);
} else {
order.setScore(1000);
addScore(order);
}
}
}*/
@Test
public void droolsOrderTest() throws Exception {
KieSession kieSession = getKieSession();
List<Order> orderList = getInitData();
for (Order order : orderList) {
// 1-规则引擎处理逻辑
kieSession.insert(order);
kieSession.fireAllRules();
// 2-执行完规则后, 执行相关的逻辑
addScore(order);
}
kieSession.dispose();
}
private static void addScore(Order o) {
System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
}
private static List<Order> getInitData() throws Exception {
List<Order> orderList = new ArrayList<>();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
{
Order order = new Order();
order.setPrice(80);
order.setBookingDate(df.parse("2015-07-01"));
User user = new User();
user.setLevel(1);
user.setName("Name1");
order.setUser(user);
order.setScore(111);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(200);
order.setBookingDate(df.parse("2015-07-02"));
User user = new User();
user.setLevel(2);
user.setName("Name2");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(800);
order.setBookingDate(df.parse("2015-07-03"));
User user = new User();
user.setLevel(3);
user.setName("Name3");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(1500);
order.setBookingDate(df.parse("2015-07-04"));
User user = new User();
user.setLevel(4);
user.setName("Name4");
order.setUser(user);
orderList.add(order);
}
return orderList;
}
}
2.2.3.3 编写积分规则生成及积分测试类
改类新生成规则,并插入到规则文件point-rules.drl,同时测试规则积分。
package com.ningzhaosheng.drools.integral.client;
import com.ningzhaosheng.drools.DroolsApplicationTests;
import com.ningzhaosheng.drools.integral.entity.Order;
import com.ningzhaosheng.drools.integral.entity.User;
import org.drools.core.impl.InternalKnowledgeBase;
import org.drools.core.impl.KnowledgeBaseFactory;
import org.junit.jupiter.api.Test;
import org.kie.api.io.ResourceType;
import org.kie.api.runtime.KieSession;
import org.kie.internal.builder.KnowledgeBuilder;
import org.kie.internal.builder.KnowledgeBuilderFactory;
import org.kie.internal.io.ResourceFactory;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* @author ningzhaosheng
* @date 2024/1/20 17:20:27
* @description 测试订单积分规则,测试手动修改规则文件,并测试规则
* 计算额外积分金额 规则如下: 订单原价金额
* 100以下, 不加分
* 100-500且用户等级大于3 加100分
* 500-1000 加500分
* 1000 以上 加1000分
*/
public class DroolsTests extends DroolsApplicationTests {
public KieSession getKieSessionFromClassPathResource() {
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
kbuilder.add(ResourceFactory.newClassPathResource("rules/point-rules.drl"), ResourceType.DRL);
//BUILD RULEBASE
InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addPackages(kbuilder.getKnowledgePackages());
//NEW WORKING MEMORY
final KieSession session = kbase.newKieSession();
return session;
}
public KieSession getKieSessionFromByte() {
String rulsStr = "package rules\n" +
"\n" +
"import com.ningzhaosheng.drools.integral.entity.Order\n" +
"import com.ningzhaosheng.drools.integral.entity.User\n" +
"\n" +
"rule \"zero\"\n" +
" no-loop true\n" +
" lock-on-active true\n" +
" salience 1\n" +
" when\n" +
" $order : Order(price <= 100)\n" +
" then\n" +
" $order.setScore(0);\n" +
" update($order);\n" +
"end\n" +
"\n" +
"rule \"add100\"\n" +
" no-loop true\n" +
" lock-on-active true\n" +
" salience 1\n" +
" when\n" +
" $order : Order(price > 100 && price <= 500)\n" +
" and $user : User(level>2)\n" +
" then\n" +
" System.out.println($order.getUser());\n" +
" $order.setScore(100);\n" +
" update($order);\n" +
"end\n" +
"\n" +
"\n" +
"rule \"add500\"\n" +
" no-loop true\n" +
" lock-on-active true\n" +
" salience 1\n" +
" when\n" +
" $order : Order(price > 500 && price <= 1000)\n" +
" then\n" +
" $order.setScore(500);\n" +
" update($order);\n" +
"end\n" +
"\n" +
"rule \"add1000\"\n" +
" no-loop true\n" +
" lock-on-active true\n" +
" salience 1\n" +
" when\n" +
" $order : Order(price > 1000)\n" +
" then\n" +
" $order.setScore(1000);\n" +
" update($order);\n" +
"end";
KnowledgeBuilder kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();
//kbuilder.add(ResourceFactory.newClassPathResource("rules/point-rules.drl"), ResourceType.DRL);
kbuilder.add(ResourceFactory.newByteArrayResource(rulsStr.getBytes()), ResourceType.DRL);
//BUILD RULEBASE
InternalKnowledgeBase kbase = KnowledgeBaseFactory.newKnowledgeBase();
kbase.addPackages(kbuilder.getKnowledgePackages());
//NEW WORKING MEMORY
final KieSession session = kbase.newKieSession();
return session;
}
@Test
public void droolsOrderTest() throws Exception {
KieSession kieSession = getKieSessionFromByte();
List<Order> orderList = getInitData();
for (Order order : orderList) {
// 1-规则引擎处理逻辑
kieSession.insert(order);
kieSession.fireAllRules();
// 2-执行完规则后, 执行相关的逻辑
addScore(order);
}
kieSession.dispose();
}
private static void addScore(Order o) {
System.out.println("用户" + o.getUser().getName() + "享受额外增加积分: " + o.getScore());
}
private static List<Order> getInitData() throws Exception {
List<Order> orderList = new ArrayList<>();
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
{
Order order = new Order();
order.setPrice(80);
order.setBookingDate(df.parse("2015-07-01"));
User user = new User();
user.setLevel(1);
user.setName("Name1");
order.setUser(user);
order.setScore(111);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(200);
order.setBookingDate(df.parse("2015-07-02"));
User user = new User();
user.setLevel(2);
user.setName("Name2");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(800);
order.setBookingDate(df.parse("2015-07-03"));
User user = new User();
user.setLevel(3);
user.setName("Name3");
order.setUser(user);
orderList.add(order);
}
{
Order order = new Order();
order.setPrice(1500);
order.setBookingDate(df.parse("2015-07-04"));
User user = new User();
user.setLevel(4);
user.setName("Name4");
order.setUser(user);
orderList.add(order);
}
return orderList;
}
}
2.2.4 测试结果
2.2.4.1 地址测试类结果(AddressDroolsTests)
2.2.4.2 订单积分规则测试类结果(OrderDroolsTests)
2.2.4.3 积分规则生成及积分测试类结果(DroolsTests)
好了,本次分享就到这里,欢迎大家继续阅读《Drools》专栏内容,Drools专栏内容暂时分享到这里,后续会上传源码到CSDN供大家下载,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!