| """ |
| 测试模块 08 —— render() 输出 |
| |
| 需求覆盖 |
| -------- |
| * R11:render(mode='ansi') 返回含 A(agent)和 G(goal)标记的字符串 |
| * R12:render 头部信息含 HitWalls 计数 |
| |
| 对应用例 |
| -------- |
| TC-20, TC-21 |
| """ |
|
|
| from __future__ import annotations |
|
|
| import pytest |
|
|
| from maze_env import MazeEnv |
|
|
|
|
| def _ansi_env() -> MazeEnv: |
| """返回 render_mode='ansi' 的确定性零障碍环境(grid=6,seed=0)。""" |
| return MazeEnv(grid_size=6, obstacle_density=0.0, seed=0, render_mode="ansi") |
|
|
|
|
| class TestRender: |
| """验证 render('ansi') 输出格式与关键标记。""" |
|
|
| |
| |
| |
|
|
| @pytest.mark.unit |
| def test_render_contains_agent_marker(self) -> None: |
| """TC-20a:render 输出包含 'A'(agent 标记)。 |
| |
| 输入: render_mode='ansi',reset(),render() |
| 期望: 'A' in rendered_str |
| 实测: 返回字符串内容 |
| """ |
| env = _ansi_env() |
| env.reset() |
| rendered = env.render() |
| assert "A" in rendered, "render 输出应包含 agent 标记 'A'" |
|
|
| @pytest.mark.unit |
| def test_render_contains_goal_marker(self) -> None: |
| """TC-20b:render 输出包含 'G'(goal 标记)。 |
| |
| 输入: render_mode='ansi',reset(),render() |
| 期望: 'G' in rendered_str |
| 实测: 返回字符串内容 |
| """ |
| env = _ansi_env() |
| env.reset() |
| rendered = env.render() |
| assert "G" in rendered, "render 输出应包含 goal 标记 'G'" |
|
|
| @pytest.mark.unit |
| def test_render_returns_string(self) -> None: |
| """TC-20c:render 返回值类型为 str(ansi 模式)。 |
| |
| 输入: render_mode='ansi',reset(),render() |
| 期望: isinstance(rendered, str) |
| 实测: type 检查 |
| """ |
| env = _ansi_env() |
| env.reset() |
| rendered = env.render() |
| assert isinstance(rendered, str), "render 应返回字符串" |
|
|
| |
| |
| |
|
|
| @pytest.mark.unit |
| def test_render_header_contains_hitwalls(self) -> None: |
| """TC-21a:render 头部含 'WallHits' 相关信息。 |
| |
| 输入: render_mode='ansi',reset(),撞墙 1 次,render() |
| 期望: render 输出含 'wall'(大小写不敏感) |
| 实测: rendered.lower() |
| """ |
| env = _ansi_env() |
| env.reset() |
| env.step(0) |
| rendered = env.render() |
| assert "wall" in rendered.lower(), \ |
| "render 头部应包含 WallHits 相关信息" |
|
|
| @pytest.mark.unit |
| def test_render_header_hitwalls_count(self) -> None: |
| """TC-21b:render 头部 WallHits 数值与实际撞墙次数一致。 |
| |
| 输入: render_mode='ansi',reset(),撞墙 2 次,render() |
| 期望: render 输出首行含 '2' |
| 实测: rendered 首行内容 |
| """ |
| env = _ansi_env() |
| env.reset() |
| env.step(0) |
| env.step(0) |
| rendered = env.render() |
| first_line = rendered.split("\n")[0] |
| assert "2" in first_line, \ |
| f"render 头部应显示 WallHits=2,实际首行:{first_line!r}" |
|
|
| @pytest.mark.unit |
| def test_render_after_move_a_moved(self) -> None: |
| """TC-21c:移动后,'A' 标记仍存在于 render 输出中。 |
| |
| 输入: render_mode='ansi',reset(),右移一步到 (1,2),render() |
| 期望: 'A' in rendered |
| 实测: 字符串包含检查 |
| """ |
| env = _ansi_env() |
| env.reset() |
| env.step(3) |
| rendered = env.render() |
| assert "A" in rendered |
|
|
| |
| |
| |
|
|
| @pytest.mark.unit |
| def test_render_human_returns_none(self, capsys) -> None: |
| """TC-22a:render_mode='human' 时 render() 打印到 stdout 并返回 None。 |
| |
| 输入: render_mode='human',reset(),render() |
| 期望: 返回值为 None,stdout 非空 |
| 实测: 返回值类型 + capsys 捕获 |
| """ |
| env = MazeEnv(grid_size=5, obstacle_density=0.0, seed=0, render_mode="human") |
| env.reset() |
| result = env.render() |
| captured = capsys.readouterr() |
| assert result is None, "human 模式 render() 应返回 None" |
| assert len(captured.out) > 0, "human 模式应向 stdout 打印内容" |
|
|
| @pytest.mark.unit |
| def test_render_none_mode_returns_none(self) -> None: |
| """TC-22b:render_mode=None 时 render() 直接返回 None,无输出。 |
| |
| 输入: MazeEnv()(默认 render_mode=None),reset(),render() |
| 期望: None |
| 实测: 返回值 |
| """ |
| env = MazeEnv(grid_size=5, obstacle_density=0.0, seed=0) |
| env.reset() |
| assert env.render() is None |
|
|
| @pytest.mark.unit |
| def test_step_triggers_human_render(self, capsys) -> None: |
| """TC-22c:render_mode='human' 时,step() 自动调用 render() 打印输出。 |
| |
| 输入: render_mode='human',reset(),step(右移) |
| 期望: stdout 非空(step 内部调用 render) |
| 实测: capsys.readouterr().out |
| """ |
| env = MazeEnv(grid_size=5, obstacle_density=0.0, seed=0, render_mode="human") |
| env.reset() |
| capsys.readouterr() |
| env.step(3) |
| captured = capsys.readouterr() |
| assert len(captured.out) > 0, "human 模式 step() 应自动触发 render 输出" |
|
|
| |
| |
| |
|
|
| @pytest.mark.unit |
| def test_close_does_not_raise(self) -> None: |
| """TC-23:close() 调用不抛出任何异常。 |
| |
| 输入: reset(),close() |
| 期望: 无异常 |
| 实测: 直接调用 |
| """ |
| env = MazeEnv(grid_size=5, obstacle_density=0.0, seed=0) |
| env.reset() |
| env.close() |
|
|