""" 工艺参数 API 测试 """ from django.test import TestCase from django.contrib.auth import get_user_model from rest_framework.test import APIClient from rest_framework import status from stateflow.models import StateParameter, State User = get_user_model() class StateParameterAPITestCase(TestCase): """工艺参数 API 测试""" def setUp(self): """设置测试数据""" # 创建用户 self.user = User.objects.create_user(username='testuser', password='testpass123') # 创建多个工艺参数 self.param1 = StateParameter.objects.create( key='color', value='红色', description='颜色参数', is_required=True, is_image_path=False ) self.param2 = StateParameter.objects.create( key='size', value='大号', description='尺寸参数', is_required=False, is_image_path=False ) self.param3 = StateParameter.objects.create( key='logo_image', value='/images/logo.png', description='Logo图片', is_required=True, is_image_path=True ) self.param4 = StateParameter.objects.create( key='material', value='纯棉', description='材料参数', is_required=False, is_image_path=False ) # 创建状态并关联参数 self.state1 = State.objects.create( name='设计状态', description='设计阶段' ) self.state1.parameters.add(self.param1, self.param3) self.state2 = State.objects.create( name='生产状态', description='生产阶段' ) self.state2.parameters.add(self.param2, self.param4) # 配置 API 客户端 self.client = APIClient() self.client.force_authenticate(user=self.user) def test_list_parameters(self): """测试获取工艺参数列表""" response = self.client.get('/api/v1/parameters/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 4) # 验证返回的数据结构 for item in response.data['results']: self.assertIn('id', item) self.assertIn('key', item) self.assertIn('value', item) self.assertIn('description', item) self.assertIn('is_required', item) self.assertIn('is_image_path', item) self.assertIn('attachment', item) self.assertIn('attachment_url', item) def test_retrieve_parameter(self): """测试获取单个工艺参数详情""" response = self.client.get(f'/api/v1/parameters/{self.param1.id}/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['key'], 'color') self.assertEqual(response.data['value'], '红色') self.assertEqual(response.data['description'], '颜色参数') self.assertEqual(response.data['is_required'], True) self.assertEqual(response.data['is_image_path'], False) def test_create_parameter(self): """测试创建工艺参数""" data = { 'key': 'weight', 'value': '500g', 'description': '重量参数', 'is_required': False, 'is_image_path': False } response = self.client.post('/api/v1/parameters/', data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data['key'], 'weight') self.assertEqual(response.data['value'], '500g') self.assertEqual(response.data['description'], '重量参数') # 验证数据库中是否创建成功 self.assertTrue(StateParameter.objects.filter(key='weight').exists()) def test_create_parameter_duplicate_key(self): """测试创建重复 key 的参数(应该失败)""" data = { 'key': 'color', # 已存在 'value': '蓝色', 'description': '另一个颜色参数', 'is_required': False, 'is_image_path': False } response = self.client.post('/api/v1/parameters/', data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertIn('key', response.data) def test_update_parameter_full(self): """测试完整更新工艺参数 (PUT)""" data = { 'key': 'color_updated', 'value': '蓝色', 'description': '更新后的颜色参数', 'is_required': False, 'is_image_path': False } response = self.client.put(f'/api/v1/parameters/{self.param1.id}/', data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['key'], 'color_updated') self.assertEqual(response.data['value'], '蓝色') self.assertEqual(response.data['is_required'], False) # 验证数据库中的更新 self.param1.refresh_from_db() self.assertEqual(self.param1.key, 'color_updated') self.assertEqual(self.param1.value, '蓝色') def test_update_parameter_partial(self): """测试部分更新工艺参数 (PATCH)""" data = { 'value': '绿色', 'description': '修改后的描述' } response = self.client.patch(f'/api/v1/parameters/{self.param1.id}/', data) self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['key'], 'color') # key 未改变 self.assertEqual(response.data['value'], '绿色') # value 已改变 self.assertEqual(response.data['description'], '修改后的描述') # 验证数据库中的更新 self.param1.refresh_from_db() self.assertEqual(self.param1.key, 'color') self.assertEqual(self.param1.value, '绿色') def test_delete_parameter_not_allowed(self): """测试删除工艺参数(应该被禁止)""" response = self.client.delete(f'/api/v1/parameters/{self.param1.id}/') self.assertEqual(response.status_code, status.HTTP_405_METHOD_NOT_ALLOWED) self.assertIn('detail', response.data) # 验证数据库中参数仍然存在 self.assertTrue(StateParameter.objects.filter(id=self.param1.id).exists()) def test_search_parameters(self): """测试搜索工艺参数""" response = self.client.get('/api/v1/parameters/?search=颜色') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['results'][0]['key'], 'color') def test_search_parameters_by_key(self): """测试按 key 搜索工艺参数""" response = self.client.get('/api/v1/parameters/?search=size') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['results'][0]['key'], 'size') def test_filter_required_parameters(self): """测试筛选必填参数""" response = self.client.get('/api/v1/parameters/?is_required=true') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 2) # color 和 logo_image for item in response.data['results']: self.assertTrue(item['is_required']) def test_filter_optional_parameters(self): """测试筛选可选参数""" response = self.client.get('/api/v1/parameters/?is_required=false') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 2) # size 和 material for item in response.data['results']: self.assertFalse(item['is_required']) def test_filter_image_path_parameters(self): """测试筛选图片路径参数""" response = self.client.get('/api/v1/parameters/?is_image_path=true') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 1) self.assertEqual(response.data['results'][0]['key'], 'logo_image') self.assertTrue(response.data['results'][0]['is_image_path']) def test_get_required_parameters_action(self): """测试获取所有必填参数的自定义 action""" response = self.client.get('/api/v1/parameters/required/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 2) keys = [item['key'] for item in response.data] self.assertIn('color', keys) self.assertIn('logo_image', keys) def test_get_optional_parameters_action(self): """测试获取所有可选参数的自定义 action""" response = self.client.get('/api/v1/parameters/optional/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 2) keys = [item['key'] for item in response.data] self.assertIn('size', keys) self.assertIn('material', keys) def test_get_parameter_states(self): """测试获取使用该参数的所有状态""" response = self.client.get(f'/api/v1/parameters/{self.param1.id}/states/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['parameter_id'], self.param1.id) self.assertEqual(response.data['parameter_key'], 'color') self.assertEqual(response.data['count'], 1) self.assertEqual(len(response.data['states']), 1) self.assertEqual(response.data['states'][0]['name'], '设计状态') def test_get_parameter_states_multiple(self): """测试获取被多个状态使用的参数""" # 让 param2 也被 state1 使用 self.state1.parameters.add(self.param2) response = self.client.get(f'/api/v1/parameters/{self.param2.id}/states/') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(response.data['count'], 2) # 被两个状态使用 state_names = [state['name'] for state in response.data['states']] self.assertIn('设计状态', state_names) self.assertIn('生产状态', state_names) def test_unauthorized_access(self): """测试未认证访问""" self.client.force_authenticate(user=None) response = self.client.get('/api/v1/parameters/') self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED) def test_create_parameter_minimal(self): """测试创建最小参数(只有必需字段)""" data = { 'key': 'simple_param' } response = self.client.post('/api/v1/parameters/', data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(response.data['key'], 'simple_param') self.assertIsNone(response.data['value']) self.assertEqual(response.data['description'], '') self.assertFalse(response.data['is_required']) self.assertFalse(response.data['is_image_path'])