1
0
forked from erp-dev/erp

feat: stateflow v2 (params required)

This commit is contained in:
2025-11-15 19:39:15 +08:00
parent 9ad404a365
commit 9c38e2ac09
24 changed files with 3670 additions and 547 deletions

View File

@@ -0,0 +1,374 @@
"""
测试参数管理功能
包括必填参数验证、参数记录创建、回退后参数可见性等
"""
from django.test import TestCase
from django.contrib.auth import get_user_model
from stateflow import models, services
User = get_user_model()
class ParameterManagementTestCase(TestCase):
"""测试参数管理功能"""
def setUp(self):
"""设置测试数据"""
# 创建测试用户
self.user = User.objects.create_user(username='testuser', password='testpass')
# 创建状态
self.state1 = models.State.objects.create(name='状态1', description='第一个状态')
self.state2 = models.State.objects.create(name='状态2', description='第二个状态')
self.state3 = models.State.objects.create(name='状态3', description='第三个状态')
# 为状态1添加必填参数
self.required_param = models.StateParameter.objects.create(
key='temperature',
value='',
is_required=True,
description='温度(必填)'
)
self.optional_param = models.StateParameter.objects.create(
key='humidity',
value='',
is_required=False,
description='湿度(可选)'
)
self.state1.parameters.add(self.required_param, self.optional_param)
# 为状态2添加必填参数
self.required_param2 = models.StateParameter.objects.create(
key='pressure',
value='',
is_required=True,
description='压力(必填)'
)
self.state2.parameters.add(self.required_param2)
# 创建流程
self.process = models.Process.objects.create(name='测试流程')
models.ProcessNode.objects.create(process=self.process, state=self.state1, order=0)
models.ProcessNode.objects.create(process=self.process, state=self.state2, order=1)
models.ProcessNode.objects.create(process=self.process, state=self.state3, order=2)
# 创建业务对象
self.business_object = models.BusinessObject.objects.create(
name='测试业务对象',
process=self.process
)
def test_advance_without_required_parameter_fails(self):
"""测试不提供必填参数时推进失败"""
# 尝试推进但不提供必填参数
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user
)
# 应该失败
self.assertFalse(success)
self.assertIn('缺失必填参数', message)
self.assertIn('temperature', message)
self.assertIsNone(state_log)
# 验证状态未改变
current_state = services.get_business_object_current_state(self.business_object)
self.assertIsNone(current_state)
# 验证没有创建状态流转记录
self.assertEqual(self.business_object.state_logs.count(), 0)
def test_advance_with_only_required_parameter_succeeds(self):
"""测试只提供必填参数时推进成功"""
# 只提供必填参数
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5' # 只提供必填的
)
# 应该成功
self.assertTrue(success)
self.assertIsNotNone(state_log)
# 验证状态已推进
current_state = services.get_business_object_current_state(self.business_object)
self.assertEqual(current_state.name, self.state1.name)
# 验证参数记录已创建
self.assertEqual(state_log.parameter_records.count(), 1)
param_record = state_log.parameter_records.first()
self.assertEqual(param_record.parameters['temperature'], '25.5')
self.assertNotIn('humidity', param_record.parameters)
def test_advance_with_all_parameters(self):
"""测试提供所有参数时推进成功"""
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5',
humidity='60%'
)
# 应该成功
self.assertTrue(success)
self.assertIsNotNone(state_log)
# 验证参数记录包含所有提供的参数
param_record = state_log.parameter_records.first()
self.assertEqual(param_record.parameters['temperature'], '25.5')
self.assertEqual(param_record.parameters['humidity'], '60%')
def test_advance_with_extra_parameters(self):
"""测试提供额外参数时也能成功(不做验证)"""
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5',
humidity='60%',
operator='张三', # 额外参数
notes='测试备注' # 额外参数
)
# 应该成功(不验证参数是否在定义中)
self.assertTrue(success)
# 验证所有参数都被保存
param_record = state_log.parameter_records.first()
self.assertEqual(len(param_record.parameters), 4)
self.assertEqual(param_record.parameters['operator'], '张三')
self.assertEqual(param_record.parameters['notes'], '测试备注')
def test_add_parameters_after_advance(self):
"""测试推进后补充参数"""
# 先推进
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5'
)
self.assertTrue(success)
# 补充参数
new_record = services.add_parameters_to_state_log(
state_log,
remark='补充测量',
humidity='65%',
inspector='李四'
)
# 验证创建了新的参数记录
self.assertEqual(state_log.parameter_records.count(), 2)
self.assertEqual(new_record.parameters['humidity'], '65%')
self.assertEqual(new_record.parameters['inspector'], '李四')
self.assertEqual(new_record.remark, '补充测量')
def test_parameter_summary_with_updates(self):
"""测试参数汇总(包含更新的值)"""
# 推进并提供初始参数
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5',
humidity='60%'
)
# 补充参数(更新 temperature
services.add_parameters_to_state_log(
state_log,
temperature='26.0', # 重新测量
remark='温度重新测量'
)
# 获取参数汇总
summary = state_log.get_all_parameters_summary()
# 验证最新值
self.assertEqual(summary['temperature'], '26.0') # 应该是更新后的值
self.assertEqual(summary['humidity'], '60%') # 保持原值
def test_parameter_history(self):
"""测试参数历史记录"""
# 推进
success, message, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5'
)
# 多次更新同一个参数
services.add_parameters_to_state_log(
state_log,
temperature='26.0',
remark='第一次重测'
)
services.add_parameters_to_state_log(
state_log,
temperature='26.5',
remark='第二次重测'
)
# 获取历史
history = state_log.get_parameter_history('temperature')
# 验证历史记录
self.assertEqual(len(history), 3)
self.assertEqual(history[0]['value'], '25.5')
self.assertEqual(history[1]['value'], '26.0')
self.assertEqual(history[1]['remark'], '第一次重测')
self.assertEqual(history[2]['value'], '26.5')
self.assertEqual(history[2]['remark'], '第二次重测')
def test_step_back_excludes_cancelled_state_parameters(self):
"""测试回退后,默认情况下查询参数时应排除已撤销状态的参数"""
# 推进两次,每次都提供参数
success, msg, state_log1 = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5',
humidity='60%'
)
self.assertTrue(success)
success, msg, state_log2 = services.advance_to_next_state(
self.business_object,
self.user,
pressure='1013'
)
self.assertTrue(success)
# 验证两个状态都有参数记录
self.assertEqual(state_log1.parameter_records.count(), 1)
self.assertEqual(state_log2.parameter_records.count(), 1)
# 回退一步(撤销 state2
success, message = services.step_back_one_state(self.business_object, self.user)
self.assertTrue(success)
# 刷新 state_log2
state_log2.refresh_from_db()
self.assertTrue(state_log2.is_cancelled)
# 默认情况下,已撤销状态的参数不可见
summary = state_log2.get_all_parameters_summary()
self.assertEqual(len(summary), 0) # 应该返回空字典
# 使用 include_cancelled=True 可以查看已撤销状态的参数
summary_with_cancelled = state_log2.get_all_parameters_summary(include_cancelled=True)
self.assertEqual(len(summary_with_cancelled), 1)
self.assertEqual(summary_with_cancelled['pressure'], '1013')
# 验证 state_log1 的参数仍然可见(未撤销)
summary1 = state_log1.get_all_parameters_summary()
self.assertEqual(len(summary1), 2)
self.assertEqual(summary1['temperature'], '25.5')
self.assertEqual(summary1['humidity'], '60%')
def test_cancelled_state_parameter_history(self):
"""测试已撤销状态的参数历史记录不可见"""
# 推进并提供参数
success, msg, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5'
)
self.assertTrue(success)
# 补充参数
services.add_parameters_to_state_log(
state_log,
temperature='26.0',
remark='重新测量'
)
# 验证参数历史存在
history = state_log.get_parameter_history('temperature')
self.assertEqual(len(history), 2)
# 回退(撤销状态)
services.step_back_one_state(self.business_object, self.user)
state_log.refresh_from_db()
# 默认情况下,已撤销状态的参数历史不可见
history = state_log.get_parameter_history('temperature')
self.assertEqual(len(history), 0)
# 使用 include_cancelled=True 可以查看
history_with_cancelled = state_log.get_parameter_history('temperature', include_cancelled=True)
self.assertEqual(len(history_with_cancelled), 2)
def test_cancelled_state_get_latest_parameter(self):
"""测试已撤销状态无法获取最新参数值"""
# 推进并提供参数
success, msg, state_log = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5'
)
self.assertTrue(success)
# 验证可以获取参数
temp = state_log.get_latest_parameter('temperature')
self.assertEqual(temp, '25.5')
# 回退(撤销状态)
services.step_back_one_state(self.business_object, self.user)
state_log.refresh_from_db()
# 默认情况下返回默认值
temp = state_log.get_latest_parameter('temperature', default='N/A')
self.assertEqual(temp, 'N/A')
# 使用 include_cancelled=True 可以获取
temp_with_cancelled = state_log.get_latest_parameter('temperature', include_cancelled=True)
self.assertEqual(temp_with_cancelled, '25.5')
def test_multiple_states_with_different_required_parameters(self):
"""测试多个状态各自的必填参数验证"""
# 推进到 state1需要 temperature
success, msg, _ = services.advance_to_next_state(
self.business_object,
self.user,
temperature='25.5'
)
self.assertTrue(success)
# 尝试推进到 state2 但不提供 pressure
success, msg, _ = services.advance_to_next_state(
self.business_object,
self.user,
temperature='26.0' # 提供了 state1 的参数,但这是 state2
)
# 应该失败(缺少 state2 的必填参数 pressure
self.assertFalse(success)
self.assertIn('缺失必填参数', msg)
self.assertIn('pressure', msg)
# 提供正确的必填参数
success, msg, _ = services.advance_to_next_state(
self.business_object,
self.user,
pressure='1013'
)
self.assertTrue(success)
def test_state_without_required_parameters_allows_advance_without_params(self):
"""测试没有必填参数的状态允许不提供参数推进"""
# 先推进两次到达 state3没有任何参数要求
services.advance_to_next_state(self.business_object, self.user, temperature='25')
services.advance_to_next_state(self.business_object, self.user, pressure='1013')
# 推进到 state3不提供任何参数
success, msg, state_log = services.advance_to_next_state(
self.business_object,
self.user
)
# 应该成功
self.assertTrue(success)
self.assertIsNotNone(state_log)
# 验证没有创建参数记录
self.assertEqual(state_log.parameter_records.count(), 0)