如何解决unittest测试中的AssertionError: !=None问题?
问题描述
我开发了名为Braves Stats的Python程序,包含lookup_player、add_player_to_dict、delete_in_dict三个球员字典操作函数,并用unittest编写测试用例。运行测试时出现AssertionError,例如test_add_player_success用例提示预期字典与None不相等。相关代码及错误信息如下:
主程序代码
import unittest def main(): #initial roster# brave_roster = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Ronald Acuna": "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266", } def lookup_player(brave_roster,name): name = input("Enter the name of the player you want to lookup:\n") if name in brave_roster: print("Here are the", [name], "stats:", brave_roster[name]) else: print("That player does not exist.") def add_player_to_dict(brave_roster,name,stats): name = input("Enter the name of the player you want to add:\n") if name not in brave_roster: stats = input("Please add stats:\n") brave_roster[name] = stats brave_roster.update([(name, stats)]) print("Here's", [name],"'s stats:\n") for name, stats in brave_roster.items(): print(name, ':', stats) else: print("That player is already on our roster.") def delete_in_dict(brave_roster, name): name = input("Enter the name of the player you want to remove:\n") if name in brave_roster: del brave_roster[name] return brave_roster else: print("\n uh typo?", [name], "does not play for us") if __name__ == '__main__': print("\t *** Braves Stats! ***\n") print("Welcome to My Braves Stats!") brave_roster = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Ronald Acuna": "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266", } name = main() choice = input("Please type your choice number:") if (choice == "1"): lookup_player(brave_roster,name) elif (choice == "2"): add_player_to_dict(brave_roster,name) else: (choice == "3") delete_in_dict(brave_roster,name) print("\nThanks for using my Braves Stats.")
测试用例代码
class TestDictFunctions(unittest.TestCase): def test_search_player_success(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } actual = test_dict["Austin Riley"] expected = lookup_player(test_dict, "Austin Riley") self.assertEqual(actual, expected) def test_search_player_no_result(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } actual = "N/A" expected = lookup_player(test_dict, "Ronald Acuna") self.assertEqual(actual, expected) def test_add_player_sucess(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } actual = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Ronald Acuna": "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266" } expected = add_player_to_dict(test_dict, "Ronald Acuna", "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266") self.assertEqual(actual, expected) def test_add_player_duplicate(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} actual = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Austin Riley(2)": "AB: 350, R: 20, H: 120, HR: 5, AVG: 0.214"} expected = add_player_to_dict(test_dict, "Austin Riley", "AB: 350, R: 20, H: 120, HR: 5, AVG: 0.214") self.assertEqual(actual, expected) def test_delete_player_sucess(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} expected = {} actual = delete_in_dict(test_dict, "Austin Riley") self.assertEqual(actual, expected) def test_delete_word_no_result(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} expected = test_dict actual = delete_in_dict(test_dict, "Shohei Ohtani") self.assertEqual(actual, expected) #uncomment to run tests unittest.main()
错误信息
FAIL: test_add_player_sucess (main.TestDictFunctions.test_add_player_sucess)
Traceback (most recent call last):
File "/Users/ray/Documents/DSCI HW/Homework 1/test_roster.py", line 100, in test_add_player_sucess
self.assertEqual(actual, expected)
AssertionError: {'Austin Riley': 'AB: 615, R: 90, H: 168,[78 chars]266'} != None
问题原因
1. 函数缺少返回值
add_player_to_dict和lookup_player函数没有定义return语句,Python默认会返回None。测试用例中直接将这两个函数的调用结果与预期字典/字符串比较,自然会出现字典 != None的断言错误。
delete_in_dict仅在删除成功时返回字典,删除失败时无返回值,同样会导致测试失败。
2. 函数内部覆盖传入参数
三个函数都在内部通过input()重新获取参数,完全忽略了测试用例传入的name和stats参数:
- 测试时程序会卡住等待手动输入,无法自动完成测试;
- 实际执行逻辑与测试用例预设的参数不符,导致结果不可控。
3. 逻辑与测试用例不匹配
add_player_to_dict中brave_roster.update([(name, stats)])是多余的,因为前面已经通过brave_roster[name] = stats完成了添加;test_add_player_duplicate预期会添加Austin Riley(2),但原函数遇到重复球员仅打印提示,不会创建新的键,测试逻辑不成立;- 主程序中
else: (choice == "3")是无效代码,应该改为elif choice == "3"。
修复方案
1. 调整函数设计,分离输入与业务逻辑
将用户输入和字典操作逻辑分离,让函数专注于处理字典,参数通过外部传入,避免在函数内使用input():
def lookup_player(brave_roster, name): if name in brave_roster: result = brave_roster[name] print(f"Here are the {name} stats: {result}") return result else: print("That player does not exist.") return "N/A" def add_player_to_dict(brave_roster, name, stats): if name not in brave_roster: brave_roster[name] = stats print(f"Here's {name}'s stats:\n") for player, stat in brave_roster.items(): print(f"{player} : {stat}") return brave_roster.copy() # 返回副本避免原字典被修改影响后续测试 else: print("That player is already on our roster.") return brave_roster.copy() def delete_in_dict(brave_roster, name): if name in brave_roster: del brave_roster[name] print(f"{name} has been removed from the roster.") return brave_roster.copy() else: print(f"\n uh typo? {name} does not play for us") return brave_roster.copy()
2. 修正测试用例
确保测试用例的预期结果与函数实际逻辑匹配:
class TestDictFunctions(unittest.TestCase): def test_search_player_success(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } actual = lookup_player(test_dict, "Austin Riley") expected = test_dict["Austin Riley"] self.assertEqual(actual, expected) def test_search_player_no_result(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } actual = lookup_player(test_dict, "Ronald Acuna") expected = "N/A" self.assertEqual(actual, expected) def test_add_player_success(self): test_dict = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273" } expected = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Ronald Acuna": "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266" } actual = add_player_to_dict(test_dict, "Ronald Acuna", "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266") self.assertEqual(actual, expected) def test_add_player_duplicate(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} expected = test_dict.copy() # 重复添加时字典不变 actual = add_player_to_dict(test_dict, "Austin Riley", "AB: 350, R: 20, H: 120, HR: 5, AVG: 0.214") self.assertEqual(actual, expected) def test_delete_player_success(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} expected = {} actual = delete_in_dict(test_dict, "Austin Riley") self.assertEqual(actual, expected) def test_delete_player_no_result(self): test_dict = {"Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273"} expected = test_dict.copy() actual = delete_in_dict(test_dict, "Shohei Ohtani") self.assertEqual(actual, expected)
3. 修正主程序语法错误
将主程序中的无效代码改为正确的分支判断:
if __name__ == '__main__': print("\t *** Braves Stats! ***\n") print("Welcome to My Braves Stats!") brave_roster = { "Austin Riley": "AB: 615, R: 90, H: 168, HR: 38, AVG: 0.273", "Ronald Acuna": "AB: 467, R: 71, H: 124, HR: 15, AVG: 0.266", } choice = input("Please type your choice number (1: lookup, 2: add, 3: delete): ") if choice == "1": name = input("Enter the name of the player you want to lookup:\n") lookup_player(brave_roster, name) elif choice == "2": name = input("Enter the name of the player you want to add:\n") stats = input("Please add stats:\n") add_player_to_dict(brave_roster, name, stats) elif choice == "3": name = input("Enter the name of the player you want to remove:\n") delete_in_dict(brave_roster, name) else: print("Invalid choice!") print("\nThanks for using my Braves Stats.")
内容的提问来源于stack exchange,提问作者Pislibsco

