File size: 5,243 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
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
"""
测试模块 07 —— 工厂方法

需求覆盖
--------
* RF2:from_config(cfg_dict) 正确映射所有参数
* RF4:from_yaml(path) 读取 config.yaml 并构造实例

对应用例
--------
TC-18, TC-19
"""

from __future__ import annotations

from pathlib import Path

import pytest
import yaml

from maze_env import MazeEnv


class TestFactory:
    """验证 from_config() 与 from_yaml() 工厂方法。"""

    # ------------------------------------------------------------------ #
    # TC-18  from_config                                                   #
    # ------------------------------------------------------------------ #

    @pytest.mark.unit
    def test_from_config_grid_size(self, cfg_dict: dict) -> None:
        """TC-18a:from_config 正确映射 grid_size=12。

        输入:  cfg_dict(grid_size=12)
        期望:  env.observation_space.shape == (4, 12, 12)
        实测:  observation_space.shape
        """
        env = MazeEnv.from_config(cfg_dict)
        assert env.observation_space.shape == (4, 12, 12)

    @pytest.mark.unit
    def test_from_config_reward_goal(self, cfg_dict: dict) -> None:
        """TC-18b:from_config 正确映射 reward_goal=200。

        输入:  cfg_dict(goal=200)
        期望:  env.reward_goal == 200.0
        实测:  env.reward_goal 属性
        """
        env = MazeEnv.from_config(cfg_dict)
        assert env.reward_goal == 200.0

    @pytest.mark.unit
    def test_from_config_reward_wall_hit(self, cfg_dict: dict) -> None:
        """TC-18c:from_config 正确映射 reward_wall_hit=-5。

        输入:  cfg_dict(wall_hit=-5)
        期望:  env.reward_wall_hit == -5.0
        实测:  env.reward_wall_hit 属性
        """
        env = MazeEnv.from_config(cfg_dict)
        assert env.reward_wall_hit == -5.0

    @pytest.mark.unit
    def test_from_config_reward_step(self, cfg_dict: dict) -> None:
        """TC-18d:from_config 正确映射 reward_step=-2。

        输入:  cfg_dict(step=-2)
        期望:  env.reward_step == -2.0
        实测:  env.reward_step 属性
        """
        env = MazeEnv.from_config(cfg_dict)
        assert env.reward_step == -2.0

    @pytest.mark.unit
    def test_from_config_max_steps(self, cfg_dict: dict) -> None:
        """TC-18e:from_config 正确映射 max_steps=300。

        输入:  cfg_dict(max_steps=300)
        期望:  env.max_steps == 300
        实测:  env.max_steps 属性
        """
        env = MazeEnv.from_config(cfg_dict)
        assert env.max_steps == 300

    @pytest.mark.unit
    def test_from_config_reset_works(self, cfg_dict: dict) -> None:
        """TC-18f:from_config 构造的环境可以正常 reset。

        输入:  from_config(cfg_dict).reset()
        期望:  obs.shape == (4, 12, 12),不抛出异常
        实测:  reset() 返回值
        """
        env = MazeEnv.from_config(cfg_dict)
        obs, info = env.reset()
        assert obs.shape == (4, 12, 12)

    # ------------------------------------------------------------------ #
    # TC-19  from_yaml                                                     #
    # ------------------------------------------------------------------ #

    @pytest.mark.integration
    def test_from_yaml_loads(self, config_yaml_path: Path) -> None:
        """TC-19a:from_yaml 读取 config.yaml 不抛出异常。

        输入:  config.yaml 文件路径
        期望:  成功返回 MazeEnv 实例
        实测:  isinstance 检查
        """
        env = MazeEnv.from_yaml(config_yaml_path)
        assert isinstance(env, MazeEnv)

    @pytest.mark.integration
    def test_from_yaml_matches_config(self, config_yaml_path: Path) -> None:
        """TC-19b:from_yaml 参数与 config.yaml 内容一致。

        输入:  config.yaml
        期望:  env.observation_space.shape[1] == cfg["maze"]["grid_size"]
               env.max_steps == cfg["maze"]["max_steps"]
               env.reward_goal == cfg["rewards"]["goal"]
        实测:  属性值(动态读取,不硬编码)
        """
        with open(config_yaml_path, "r", encoding="utf-8") as fh:
            cfg = yaml.safe_load(fh)

        expected_grid_size = cfg["maze"]["grid_size"]
        expected_max_steps = cfg["maze"]["max_steps"]
        expected_goal      = float(cfg["rewards"]["goal"])

        env = MazeEnv.from_yaml(config_yaml_path)
        assert env.observation_space.shape[1] == expected_grid_size, \
            f"grid_size 应为 {expected_grid_size}"
        assert env.max_steps == expected_max_steps, \
            f"max_steps 应为 {expected_max_steps}(来自 config.yaml),实际 {env.max_steps}"
        assert env.reward_goal == expected_goal, \
            f"reward_goal 应为 {expected_goal}"

    @pytest.mark.integration
    def test_from_yaml_reset_works(self, config_yaml_path: Path) -> None:
        """TC-19c:from_yaml 构造的环境可以正常 reset 并产生正确形状的 obs。

        输入:  from_yaml(config_yaml_path).reset()
        期望:  obs.shape == (4, 10, 10)
        实测:  reset() 返回值
        """
        env = MazeEnv.from_yaml(config_yaml_path)
        obs, _ = env.reset()
        assert obs.shape == (4, 10, 10)