测试¶
MolPy 用 pytest 做测试。测试文件放在 tests/ 下,目录结构跟包一一对应:tests/test_core/、tests/test_io/、tests/test_parser/ 等等。
运行测试¶
pytest tests/ -v -m "not external" # 标准本地运行
pytest tests/test_core/test_frame.py -v # 单个文件
pytest tests/test_core/test_frame.py::test_creation -v # 单个测试
pytest tests/ -k "lammps" -v # 关键字过滤
pytest --cov=src/molpy tests/ -v --cov-report=term # 带覆盖率
-m "not external" 排除需要外部可执行文件(LAMMPS、Packmol、AmberTools)的测试。本地开发和 CI 默认都走这个配置。
测试内容¶
每加一个新行为,就要补一个对应的测试。覆盖四类场景:
- 正常路径——正常输入下能否返回正确结果?
- 边界情况——空输入、单元素、边界值
- 错误处理——非法输入时抛出正确的异常
- 回归测试——修完 bug,加一个测试确认它不会再冒出来
MolPy 特有代码还有两类常见测试模式:
不可变性检查——验证操作返回新对象,不改输入。
def test_typify_does_not_mutate():
original = build_test_mol()
result = typifier.typify(original)
assert result is not original
assert len(original.atoms) == original_count
往返测试——对 I/O 格式,写出去再读回来,确认数据不变。
def test_pdb_round_trip(tmp_path):
write_pdb(tmp_path / "out.pdb", frame)
restored = read_pdb(tmp_path / "out.pdb")
assert restored["atoms"].nrows == frame["atoms"].nrows
标记(Markers)¶
需要外部可执行文件的测试,用 @pytest.mark.external 标记:
这样没装对应工具的机器也能跑默认测试套件,不会报错。
编写良好的测试¶
断言行为,不是断言实现细节。测试只应在可观察结果变化时失败,重构内部实现不影响它。Fixture 保持小巧——为了测一个键操作就搭 100 个原子,那测试范围太大了。文件 I/O 测试用 tmp_path fixture,别污染工作目录。