File size: 3,858 Bytes
fe0625d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"""
测试模块 03 —— 随机性与可复现性

需求覆盖
--------
* R1:seed 参数控制可复现性
* RF1:BFS 连通性保证(起终点强制可达)

对应用例
--------
TC-08, TC-09, TC-10
"""

from __future__ import annotations

import numpy as np
import pytest

from maze_env import MazeEnv


class TestRandomness:
    """验证 BFS 连通性、seed 可复现性及不同 seed 产生不同地图。"""

    # ------------------------------------------------------------------ #
    # TC-08  BFS 连通性压力测试                                             #
    # ------------------------------------------------------------------ #

    @pytest.mark.slow
    def test_bfs_connectivity_pressure(self, env_dense: MazeEnv) -> None:
        """TC-08:高密度障碍下,连续 50 次 reset 均保证起终点可达。

        输入:  MazeEnv(grid_size=10, obstacle_density=0.45),reset() × 50
        期望:  每次 reset 后,obs[1](agent)与 obs[2](goal)均有唯一激活格,
               且地图合法(不抛出异常,obs shape 正确)
        实测:  检查 obs shape 及通道 sum
        """
        for i in range(50):
            obs, info = env_dense.reset()
            assert obs.shape == (4, 10, 10), f"第 {i} 次 reset shape 错误"
            assert float(obs[1].sum()) == 1.0, f"第 {i} 次 reset agent 通道异常"
            assert float(obs[2].sum()) == 1.0, f"第 {i} 次 reset goal 通道异常"

    # ------------------------------------------------------------------ #
    # TC-09  相同 seed 可复现                                               #
    # ------------------------------------------------------------------ #

    @pytest.mark.unit
    def test_same_seed_reproducible(self) -> None:
        """TC-09:相同 seed 两次 reset,产生完全相同的地图与 obs。

        输入:  两个独立实例均使用 seed=42,各调用 reset()
        期望:  obs1 与 obs2 逐元素相等(np.array_equal)
        实测:  np.array_equal(obs1, obs2)
        """
        env_a = MazeEnv(grid_size=8, obstacle_density=0.3, seed=42)
        env_b = MazeEnv(grid_size=8, obstacle_density=0.3, seed=42)
        obs_a, _ = env_a.reset()
        obs_b, _ = env_b.reset()
        assert np.array_equal(obs_a, obs_b), "相同 seed 产生的地图应完全一致"

    @pytest.mark.unit
    def test_same_seed_reset_twice_reproducible(self) -> None:
        """TC-09b:同一实例用相同 seed 调用两次 reset(),结果相同。

        输入:  env.reset(seed=5),env.reset(seed=5)
        期望:  两次 obs 完全相等
        实测:  np.array_equal
        """
        env = MazeEnv(grid_size=6, obstacle_density=0.2)
        obs_first, _  = env.reset(seed=5)
        obs_second, _ = env.reset(seed=5)
        assert np.array_equal(obs_first, obs_second), \
            "同一实例以相同 seed 重置,结果应可复现"

    # ------------------------------------------------------------------ #
    # TC-10  不同 seed 产生不同地图                                         #
    # ------------------------------------------------------------------ #

    @pytest.mark.unit
    def test_different_seeds_different_maps(self) -> None:
        """TC-10:不同 seed 应产生不同的 wall_map(obs[0])。

        输入:  seed=0 与 seed=1,obstacle_density=0.3,grid_size=10
        期望:  obs_0[0] != obs_1[0](至少有一个元素不同)
        实测:  not np.array_equal(obs_0[0], obs_1[0])
        """
        env_0 = MazeEnv(grid_size=10, obstacle_density=0.3, seed=0)
        env_1 = MazeEnv(grid_size=10, obstacle_density=0.3, seed=1)
        obs_0, _ = env_0.reset()
        obs_1, _ = env_1.reset()
        assert not np.array_equal(obs_0[0], obs_1[0]), \
            "不同 seed 应产生不同的墙壁地图"