如何用pytest-cov覆盖server.py中if __name__ == '__main__'代码块?
解决server.py中
if __name__ == '__main__'代码块的覆盖率问题 问题原因
测试执行时,server.py是以模块形式被import的,此时__name__的值为'server',而非'__main__',因此该代码块不会被执行,导致覆盖率工具无法统计到这部分代码。
解决方案
方案一:直接在测试中触发main代码块执行
在testing.py中新增测试用例,通过修改模块名并结合mock避免服务阻塞的方式触发该代码块:
def test_main_block(): # 保存原模块名 original_name = server.__name__ # 修改为__main__以触发目标代码块 server.__name__ = '__main__' # 用mock跳过app.run的阻塞逻辑,防止测试卡住 import mock with mock.patch('server.app.run') as mock_run: import importlib importlib.reload(server) # 验证app.run被正确调用 mock_run.assert_called_once_with(port=5000, debug=True) # 恢复原模块名,避免影响其他测试 server.__name__ = original_name
方案二:重构server.py代码(推荐)
将if __name__ == '__main__'中的逻辑封装为独立函数,既提升代码可维护性,也便于单独测试:
修改server.py:
def init_database_and_start_server(): with app.app_context(): db.drop_all() # 清空现有数据库表 db.create_all() # 创建新表 app.run(port=5000, debug=True) if __name__ == '__main__': init_database_and_start_server()
然后在testing.py中添加对应测试:
def test_init_database(): # 测试数据库初始化逻辑 with server.app.app_context(): # 验证drop_all和create_all的执行效果 server.db.create_all() server.db.drop_all() assert not server.db.engine.dialect.has_table(server.db.engine.connect(), 'user') server.db.create_all() assert server.db.engine.dialect.has_table(server.db.engine.connect(), 'user') def test_main_entry_point(): # 测试main入口是否正确调用封装函数 import mock with mock.patch('server.init_database_and_start_server') as mock_func: server.__name__ = '__main__' import importlib importlib.reload(server) mock_func.assert_called_once()
两种方案对比
- 方案一无需修改业务代码,但依赖模块重载和mock,逻辑相对繁琐;
- 方案二通过代码重构提升了可测试性,同时让业务逻辑更清晰,更适合长期维护。
内容的提问来源于stack exchange,提问作者Bart
相关产品推荐
相关产品推荐

