| """tests/test_bfs.py —— BFS 寻路算法单元测试 |
| |
| 覆盖范围 |
| -------- |
| TC-1 标准唯一通路 |
| TC-2 起点与终点重合 |
| TC-3 绝对无解(终点被墙封死) |
| TC-4 多条通路最优性(BFS 必须返回最短路) |
| TC-5 起点本身是墙(非法输入) |
| TC-6 性能基准:10×10 空旷地图 < 2ms |
| """ |
|
|
| from __future__ import annotations |
|
|
| import numpy as np |
|
|
| from maze_env.bfs import bfs |
|
|
|
|
| |
| |
| |
|
|
| def test_standard_path() -> None: |
| """TC-1:唯一通路,验证 success / steps / path 首尾 / 路径长度一致性。 |
| |
| 地图:: |
| |
| █ █ █ █ █ |
| █ · · · █ |
| █ █ █ · █ |
| █ █ █ · █ |
| █ █ █ █ █ |
| |
| 起点 (1,1) → 终点 (3,3),唯一通路共 4 步。 |
| """ |
| grid = np.array([ |
| [1, 1, 1, 1, 1], |
| [1, 0, 0, 0, 1], |
| [1, 1, 1, 0, 1], |
| [1, 1, 1, 0, 1], |
| [1, 1, 1, 1, 1], |
| ], dtype=np.int32) |
| r = bfs(grid, start=(1, 1), end=(3, 3)) |
|
|
| assert r["success"] is True |
| assert r["steps"] == 4 |
| assert r["path"][0] == (1, 1) |
| assert r["path"][-1] == (3, 3) |
| assert len(r["path"]) == r["steps"] + 1 |
| assert isinstance(r["execution_time_ms"], float) |
|
|
|
|
| |
| |
| |
|
|
| def test_same_start_end() -> None: |
| """TC-2:起点与终点重合,steps=0,path=[start]。""" |
| grid = np.array([ |
| [1, 1, 1], |
| [1, 0, 1], |
| [1, 1, 1], |
| ], dtype=np.int32) |
| r = bfs(grid, start=(1, 1), end=(1, 1)) |
|
|
| assert r["success"] is True |
| assert r["steps"] == 0 |
| assert r["path"] == [(1, 1)] |
|
|
|
|
| |
| |
| |
|
|
| def test_no_path_enclosed() -> None: |
| """TC-3:终点被墙封死,无任何通路,优雅返回 False。 |
| |
| 地图:: |
| |
| · █ █ █ █ |
| █ █ █ █ █ |
| █ █ · █ █ |
| █ █ █ █ █ |
| █ █ █ █ █ |
| |
| 起点 (0,0) 孤立,终点 (2,2) 被墙完全包围,两者均无通路。 |
| """ |
| grid = np.array([ |
| [0, 1, 1, 1, 1], |
| [1, 1, 1, 1, 1], |
| [1, 1, 0, 1, 1], |
| [1, 1, 1, 1, 1], |
| [1, 1, 1, 1, 1], |
| ], dtype=np.int32) |
| r = bfs(grid, start=(0, 0), end=(2, 2)) |
|
|
| assert r["success"] is False |
| assert r["steps"] == -1 |
| assert r["path"] == [] |
|
|
|
|
| |
| |
| |
|
|
| def test_multiple_paths_shortest() -> None: |
| """TC-4:多条通路最优性验证 —— BFS 必须返回最短路,而非 DFS 的长路。 |
| |
| 设计说明 |
| -------- |
| 6×6 开放网格(仅保留外围墙),起点 (1,1) 终点 (4,4)。 |
| 同时存在多条通路;曼哈顿距离下界 = |4-1| + |4-1| = 6。 |
| |
| 断言 steps == 6 验证 BFS 返回最短路,而非 DFS / 随机游走可能返回的冗长路径。 |
| """ |
| grid = np.array([ |
| [1, 1, 1, 1, 1, 1], |
| [1, 0, 0, 0, 0, 1], |
| [1, 0, 0, 0, 0, 1], |
| [1, 0, 0, 0, 0, 1], |
| [1, 0, 0, 0, 0, 1], |
| [1, 1, 1, 1, 1, 1], |
| ], dtype=np.int32) |
| r = bfs(grid, start=(1, 1), end=(4, 4)) |
|
|
| assert r["success"] is True |
| |
| assert r["steps"] == 6, ( |
| f"BFS 最优性失败:期望最短步数 6(曼哈顿距离),实际得到 {r['steps']}。" |
| "若此断言失败,说明算法使用了 DFS 或其他非最短路策略。" |
| ) |
| assert r["path"][0] == (1, 1) |
| assert r["path"][-1] == (4, 4) |
| |
| for i in range(len(r["path"]) - 1): |
| rr, rc = r["path"][i] |
| nr, nc = r["path"][i + 1] |
| assert abs(nr - rr) + abs(nc - rc) == 1, ( |
| f"路径第 {i}→{i+1} 步不是四邻域移动:{r['path'][i]}→{r['path'][i+1]}" |
| ) |
|
|
|
|
| |
| |
| |
|
|
| def test_start_is_wall() -> None: |
| """TC-5:起点本身是墙(非法输入),立即返回 success=False。""" |
| grid = np.array([ |
| [1, 1, 1], |
| [1, 0, 1], |
| [1, 1, 1], |
| ], dtype=np.int32) |
| r = bfs(grid, start=(0, 0), end=(1, 1)) |
|
|
| assert r["success"] is False |
| assert r["steps"] == -1 |
| assert r["path"] == [] |
|
|
|
|
| |
| |
| |
|
|
| def test_performance_10x10_empty() -> None: |
| """TC-6:性能基准 —— 10×10 空旷地图单次 BFS 耗时必须 < 2ms。 |
| |
| 设计说明 |
| -------- |
| 10×10 地图(外围墙 + 全内部可通行),起点 (1,1) 终点 (8,8), |
| 最大可能节点数 = 8×8 = 64,BFS 应在亚毫秒级完成。 |
| |
| 若此断言失败,说明实现存在严重性能缺陷(如在循环内做 O(N) 查找), |
| 应检查 visited 是否使用 set(而非 list)。 |
| """ |
| grid = np.ones((10, 10), dtype=np.int32) |
| grid[1:9, 1:9] = 0 |
|
|
| result = bfs(grid, start=(1, 1), end=(8, 8)) |
|
|
| assert result["success"] is True, "10×10 空旷地图应能找到路径" |
| assert result["steps"] == 14, ( |
| f"10×10 空旷地图最短步数期望 14(曼哈顿距离),实际 {result['steps']}" |
| ) |
| |
| assert result["execution_time_ms"] < 2.0, ( |
| f"BFS 性能不达标:10×10 地图耗时 {result['execution_time_ms']:.4f}ms," |
| f"阈值 2.0ms。请检查 visited 集合实现(应为 set,而非 list)。" |
| ) |
|
|