@pytest.mark.jcwork class TestJCWorkApi: def setup_class(self): self.token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhdXRvMTFAcXEuY29tIiwiaXNTZXRQd2QiOjEsImFjY291bnRMZXZlbCI6IjEiLCJ1c2VyTmFtZSI6ImF1dG8xMUBxcS5jb20iLCJ1c2VySWQiOjI0OTcxNjk5NjMwMCwidXNlckNvZGUiOiIyNmQ5OWI5MGVlZGY1ZjJiNWY2Mjk5NjViYTQ0OTJjZiIsImFjY291bnRJZCI6IjI0OTcxNjk5NjMwMCIsInNjb3BlIjoiYXV0aCIsImxhc3RBdXRoVGltZSI6MTc1MTYzNDEyNzQ5NCwic2lnblR5cGUiOiJVUCIsImV4cCI6MTc1NDIyNjEyNywiZGV2aWNlIjoid2ViIn0.iaDGkPq4OE-M6eedgxwRMuCTDPBa0B06aBn9DNPeFS21B9NUlH06dIEN4dU-wjTz0wo7bbw3vVRxG6PXDNv0FXFrVI27Cdizmij_CCvpekqqwXGO4qxfHn4hCMaztLpqFVOEGkKZ60VrqAstXWYAArX6PKWMZl9ObDHa4a8XAfY" # 这里替换成实际的Token或从配置读取 self.api = JCWorkApi(token=self.token) @pytest.mark.parametrize("activity_id", ["312902218894402"]) # 可以配置多个id进行测试 @allure.story("申请活动接口") def test_apply_activity(self, activity_id): allure.dynamic.title(f"申请活动ID: {activity_id}") logger.info(f"开始申请活动,活动ID:{activity_id}") res = self.api.apply_activity(activity_id) logger.info(f"返回的状态码:{res.status_code}") # 记录响应内容(非500错误时才记录) logger.info(f"返回的内容:{res.json()}") result = res.json() print(result) # 断言请求成功 assert res.status_code == 200, "请求失败,状态码不为200" # 根据实际返回结构验证的断言 assert "code" in result, "返回数据中缺少'code'字段" # 特殊处理500错误 if result["code"] == 500: error_message = "接口返回500错误:需要开发人员上传新用户token,因为一个用户token只能提交一次申请活动" logger.warning(error_message) allure.dynamic.description(error_message) # 在Allure报告中添加描述 pytest.skip(error_message) # 跳过当前测试用例 return assert result["code"] == 200, f"返回的code不为200,实际为{result['code']}" # 验证data字段存在 assert "data" in result, "返回数据中缺少'data'字段" # 验证必要字段 required_fields = ["applyId", "status"] for field in required_fields: assert field in result["data"], f"返回数据中的'data'缺少'{field}'字段" 以上脚本跑完后报错内容如下,请做对应修改:FAILED [ 12%]{'biz': 'spot', 'code': 200, 'msg': 'SUCCESS', 'msgInfo': [], 'data': True} [2025-07-07 12:02:08,596][test_rewards_hub.py 28][INFO]: 开始申请活动,活动ID:312902218894402 [2025-07-07 12:02:10,043][test_rewards_hub.py 31][INFO]: 返回的状态码:200 [2025-07-07 12:02:10,044][test_rewards_hub.py 35][INFO]: 返回的内容:{'biz': 'spot', 'code': 200, 'msg': 'SUCCESS', 'msgInfo': [], 'data': True} testcase\Rewards_Hub\test_rewards_hub.py:23 (TestJCWorkApi.test_apply_activity[312902218894402]) test_rewards_hub.py:59: in test_apply_activity assert field in result["data"], f"返回数据中的'data'缺少'{field}'字段" E TypeError: argument of type 'bool' is not iterable
时间: 2025-07-24 07:36:05 浏览: 7
<think>我们遇到了一个错误:`TypeError: argument of type 'bool' is not iterable`。
错误发生在这一行:`assert field in result["data"], f"返回数据中的'data'缺少'{field}'字段"`
原因是:当接口返回成功时,`result["data"]`是一个布尔值(True),而不是一个字典或对象。因此,我们不能使用`in`操作符来检查字段是否存在。
根据日志,返回的数据结构是:
{'biz': 'spot', 'code': 200, 'msg': 'SUCCESS', 'msgInfo': [], 'data': True}
所以,在成功的情况下,`data`字段是一个布尔值,而不是一个包含`applyId`和`status`的对象。
因此,我们需要修改测试用例,以处理两种不同的情况:
1. 当`code`为200时,`data`可能是布尔值(表示操作成功),但可能不包含`applyId`和`status`字段。
2. 或者,根据接口文档,申请活动成功时返回的数据结构可能并不是我们之前预期的那样。
根据错误信息,我们是在尝试检查`applyId`和`status`是否存在于`result["data"]`中,而`result["data"]`是True(布尔值),所以导致类型错误。
解决方案:
我们需要调整测试用例,使其能够正确处理`data`字段为布尔值的情况。
具体修改:
1. 在成功的情况下(code为200),我们可能不需要检查`applyId`和`status`,因为返回的`data`是布尔值。
2. 或者,根据接口实际返回,我们可能需要移除对`data`字段中具体字段的检查。
但是,根据测试用例的意图,我们可能期望在申请活动成功后返回一个包含申请ID和状态的对象。然而,实际返回的是布尔值True。
因此,我们需要与开发人员确认接口规范:
- 成功申请活动时,接口应该返回什么?是布尔值True,还是一个包含申请ID和状态的对象?
如果接口规范就是返回布尔值True,那么我们就需要修改测试用例,不再检查`applyId`和`status`。
如果接口规范应该是返回一个对象,那么就是接口实现有误。
由于我们无法立即确认,这里我们根据实际情况调整测试用例:
根据日志,返回的`data`是True,所以我们可以这样修改:
- 当`code`为200时,我们不再检查`data`中的具体字段,而是检查`data`是否为True(或者根据情况,如果是布尔值,我们就验证它是True)。
修改后的步骤:
1. 如果`code`为200,则验证`data`为True(或者为预期的布尔值)。
2. 如果`code`为500,则跳过。
因此,修改测试用例中的断言部分:
原代码:
# 验证必要字段
required_fields = ["applyId", "status"]
for field in required_fields:
assert field in result["data"], f"返回数据中的'data'缺少'{field}'字段"
修改为:
if result["code"] == 200:
# 根据实际返回,data可能是布尔值True,所以我们验证data为True
assert result["data"] is True, f"返回的data不为True,实际为{result['data']}"
同时,我们也可以考虑移除对`data`字段的字典检查,因为现在它可能是布尔值。
但是,请注意,我们之前还有一句断言:`assert "data" in result`,这是检查`data`字段是否存在,它可以是任何类型。
因此,完整修改如下:
- 删除对`data`字段中具体字段的检查,改为在成功时检查`data`为True。
修改后的测试方法代码:
```python
@pytest.mark.jcwork
class TestJCWorkApi:
def setup_class(self):
self.token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhdXRvMTFAcXEuY29tIiwiaXNTZXRQd2QiOjEsImFjY291bnRMZXZlbCI6IjEiLCJ1c2VyTmFtZSI6ImF1dG8xMUBxcS5jb20iLCJ1c2VySWQiOjI0OTcxNjk5NjMwMCwidXNlckNvZGUiOiIyNmQ5OWI5MGVlZGY1ZjJiNWY2Mjk5NjViYTQ0OTJjZiIsImFjY291bnRJZCI6IjI0OTcxNjk5NjMwMCIsInNjb3BlIjoiYXV0aCIsImxhc3RBdXRoVGltZSI6MTc1MTYzNDEyNzQ5NCwic2lnblR5cGUiOiJVUCIsImV4cCI6MTc1NDIyNjEyNywiZGV2aWNlIjoid2ViIn0.iaDGkPq4OE-M6eedgxwRMuCTDPBa0B06aBn9DNPeFS21B9NUlH06dIEN4dU-wjTz0wo7bbw3vVRxG6PXDNv0FXFrVI27Cdizmij_CCvpekqqwXGO4qxfHn4hCMaztLpqFVOEGkKZ60VrqAstXWYAArX6PKWMZl9ObDHa4a8XAfY"
# 这里替换成实际的Token或从配置读取
self.api = JCWorkApi(token=self.token)
@pytest.mark.parametrize("activity_id", ["312902218894402"]) # 可以配置多个id进行测试
@allure.story("申请活动接口")
def test_apply_activity(self, activity_id):
allure.dynamic.title(f"申请活动ID: {activity_id}")
logger.info(f"开始申请活动,活动ID:{activity_id}")
res = self.api.apply_activity(activity_id)
logger.info(f"返回的状态码:{res.status_code}")
# 记录响应内容(非500错误时才记录)
# 注意:即使返回500,我们也记录,但注意如果500可能导致没有json,所以需要处理
try:
result = res.json()
logger.info(f"返回的内容:{result}")
except Exception as e:
logger.error(f"解析响应内容失败: {str(e)}")
pytest.fail(f"解析响应内容失败: {str(e)}")
return
# 断言请求成功(HTTP状态码)
assert res.status_code == 200, "请求失败,状态码不为200"
# 根据实际返回结构验证的断言
assert "code" in result, "返回数据中缺少'code'字段"
# 特殊处理500错误
if result["code"] == 500:
error_message = "接口返回500错误:需要开发人员上传新用户token,因为一个用户token只能提交一次申请活动"
logger.warning(error_message)
allure.dynamic.description(error_message) # 在Allure报告中添加描述
pytest.skip(error_message) # 跳过当前测试用例
return
# 验证业务状态码为200
assert result["code"] == 200, f"返回的code不为200,实际为{result['code']}"
# 验证data字段存在
assert "data" in result, "返回数据中缺少'data'字段"
# 修改点:根据实际返回,当成功时data是布尔值True,所以我们验证它为True
# 注意:根据接口,成功时可能返回True,所以我们检查data为True
assert result["data"] is True, f"返回的data不为True,实际为{result['data']}"
# 移除之前对data字段中具体字段的检查,因为返回的是布尔值
# 原代码:检查applyId和status,现在不需要了
```
这样修改后,当成功时,我们检查`data`为True,而不是检查它是否包含某些字段。
### 修改说明
1. **错误原因**:测试用例期望`data`字段是一个字典(以便检查其中的字段),但实际返回的是布尔值,导致`in`操作符无法使用。
2. **修改内容**:
- 移除了对`data`字段中具体字段(`applyId`和`status`)的检查。
- 改为在成功时断言`data`字段为`True`。
3. **异常处理优化**:
- 添加了在解析响应JSON时的异常处理,避免因为解析失败导致测试用例无法继续。
4. **日志优化**:
- 将响应内容的日志记录放在了解析之后,这样即使解析失败也能记录原始响应文本(但这里我们记录的是解析后的结果,如果需要记录原始文本,可以额外记录`res.text`)。
### 注意事项
- 如果接口在不同情况下返回不同类型(例如,有时返回布尔值,有时返回对象),则需要更复杂的处理逻辑。
- 建议与开发团队确认接口返回规范,确保测试用例的准确性。
§§相关问题§§:
1. 如何处理API返回数据类型不一致的情况?
2. 在自动化测试中,如何设计灵活的响应验证机制?
3. 如何避免因API变更导致的测试用例失败?
4. 在测试框架中,如何实现可复用的响应验证工具?</think>### 错误分析及修复方案
错误发生在测试断言部分:
```python
required_fields = ["applyId", "status"]
for field in required_fields:
assert field in result["data"], f"返回数据中的'data'缺少'{field}'字段"
```
错误信息:`TypeError: argument of type 'bool' is not iterable`
原因分析:
1. 接口成功响应时返回的 `data` 字段是布尔值 `True`,而不是字典或对象
2. 代码尝试在布尔值上使用 `in` 操作符(用于检查字典键是否存在),但布尔值不支持这种操作
3. 测试用例的断言逻辑假设 `data` 字段是一个包含 `applyId` 和 `status` 的对象,但实际响应是布尔值
### 修复后的测试脚本
```python
@pytest.mark.jcwork
class TestJCWorkApi:
def setup_class(self):
self.token = "eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhdXRvMTFAcXEuY29tIiwiaXNTZXRQd2QiOjEsImFjY291bnRMZXZlbCI6IjEiLCJ1c2VyTmFtZSI6ImF1dG8xMUBxcS5jb20iLCJ1c2VySWQiOjI0OTcxNjk5NjMwMCwidXNlckNvZGUiOiIyNmQ5OWI5MGVlZGY1ZjJiNWY2Mjk5NjViYTQ0OTJjZiIsImFjY291bnRJZCI6IjI0OTcxNjk5NjMwMCIsInNjb3BlIjoiYXV0aCIsImxhc3RBdXRoVGltZSI6MTc1MTYzNDEyNzQ5NCwic2lnblR5cGUiOiJVUCIsImV4cCI6MTc1NDIyNjEyNywiZGV2aWNlIjoid2ViIn0.iaDGkPq4OE-M6eedgxwRMuCTDPBa0B06aBn9DNPeFS21B9NUlH06dIEN4dU-wjTz0wo7bbw3vVRxG6PXDNv0FXFrVI27Cdizmij_CCvpekqqwXGO4qxfHn4hCMaztLpqFVOEGkKZ60VrqAstXWYAArX6PKWMZl9ObDHa4a8XAfY"
# 这里替换成实际的Token或从配置读取
self.api = JCWorkApi(token=self.token)
@pytest.mark.parametrize("activity_id", ["312902218894402"]) # 可以配置多个id进行测试
@allure.story("申请活动接口")
def test_apply_activity(self, activity_id):
allure.dynamic.title(f"申请活动ID: {activity_id}")
logger.info(f"开始申请活动,活动ID:{activity_id}")
res = self.api.apply_activity(activity_id)
logger.info(f"返回的状态码:{res.status_code}")
# 记录响应内容(非500错误时才记录)
try:
result = res.json()
logger.info(f"返回的内容:{result}")
except Exception as e:
logger.error(f"JSON解析失败: {str(e)}")
pytest.fail(f"JSON解析失败: {str(e)}")
return
# 断言请求成功
assert res.status_code == 200, "请求失败,状态码不为200"
# 根据实际返回结构验证的断言
assert "code" in result, "返回数据中缺少'code'字段"
# 特殊处理500错误
if result["code"] == 500:
error_message = "接口返回500错误:需要开发人员上传新用户token,因为一个用户token只能提交一次申请活动"
logger.warning(error_message)
allure.dynamic.description(error_message) # 在Allure报告中添加描述
pytest.skip(error_message) # 跳过当前测试用例
return
assert result["code"] == 200, f"返回的code不为200,实际为{result['code']}"
# 验证data字段存在
assert "data" in result, "返回数据中缺少'data'字段"
# 修复点:根据实际响应类型进行验证
if isinstance(result["data"], bool):
# 当data是布尔值时,验证它为True
assert result["data"] is True, (
f"data字段应为True,实际为{result['data']}"
)
elif isinstance(result["data"], dict):
# 当data是字典时,验证必要字段
required_fields = ["applyId", "status"]
for field in required_fields:
assert field in result["data"], (
f"返回数据中的'data'缺少'{field}'字段"
)
else:
# 处理其他类型的情况
pytest.fail(f"data字段类型异常: {type(result['data'])}")
```
### 修改说明
1. **添加响应类型检查**:
```python
# 修复点:根据实际响应类型进行验证
if isinstance(result["data"], bool):
# 当data是布尔值时,验证它为True
assert result["data"] is True, (
f"data字段应为True,实际为{result['data']}"
)
elif isinstance(result["data"], dict):
# 当data是字典时,验证必要字段
required_fields = ["applyId", "status"]
for field in required_fields:
assert field in result["data"], (
f"返回数据中的'data'缺少'{field}'字段"
)
else:
# 处理其他类型的情况
pytest.fail(f"data字段类型异常: {type(result['data'])}")
```
- 根据实际响应类型进行不同的验证
- 当 `data` 是布尔值时,验证它为 `True`
- 当 `data` 是字典时,验证包含必要字段
- 处理其他类型的情况
2. **增强异常处理**:
```python
try:
result = res.json()
logger.info(f"返回的内容:{result}")
except Exception as e:
logger.error(f"JSON解析失败: {str(e)}")
pytest.fail(f"JSON解析失败: {str(e)}")
return
```
- 添加更健壮的JSON解析错误处理
- 记录详细的错误信息
3. **保留原有逻辑**:
- 保留HTTP状态码验证
- 保留500错误处理逻辑
- 保留基本字段验证(`code`、`data`)
### 错误原因分析
1. **接口行为不一致**:
- 接口在成功时返回布尔值 `True`,而不是包含详细信息的对象
- 测试用例假设接口总是返回对象,导致类型错误
2. **缺少类型检查**:
- 测试代码没有检查 `data` 字段的类型就直接尝试访问其属性
- 应该先验证类型再执行相关操作
3. **接口文档不匹配**:
- 实际接口行为可能与文档描述不一致
- 需要确认接口规范:成功时应该返回布尔值还是对象
### 建议后续步骤
1. **确认接口规范**:
- 与开发团队确认接口在成功时应返回的数据结构
- 确定 `data` 字段何时为布尔值,何时为对象
2. **添加更多测试用例**:
- 测试不同活动ID的情况
- 测试重复申请的情况
- 测试无效活动ID的情况
3. **改进API封装**:
- 在API封装层添加响应解析和类型转换
- 返回统一的数据结构,简化测试验证
阅读全文
相关推荐



















