Files
cultivation-world-simulator/tests/test_action_self_heal.py
2026-01-08 00:33:41 +08:00

141 lines
5.7 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import pytest
from unittest.mock import MagicMock, patch
from src.classes.action.self_heal import SelfHeal
from src.classes.sect_region import SectRegion
from src.classes.region import NormalRegion
from src.classes.tile import Tile, TileType
from src.classes.sect import Sect
from src.classes.hp import HP
class TestSelfHealAction:
@pytest.fixture
def healing_avatar(self, dummy_avatar):
"""
基于 dummy_avatar 扩展,
设置 HP 为半血,以便可以进行疗伤。
"""
dummy_avatar.hp = HP(100, 50) # 50/100 HP
# effects 是 property无法直接赋值需要 mock 或者通过 effects mixin 覆盖
# 这里 dummy_avatar 使用了 Real Avatar 类,所以 effects property 会去读 self._effects 或者计算
return dummy_avatar
@pytest.fixture
def sect_region(self):
return SectRegion(id=999, name="青云门总部", desc="测试宗门总部")
@pytest.fixture
def normal_region(self):
return NormalRegion(id=101, name="荒野", desc="测试荒野")
@pytest.fixture
def mock_sect(self, sect_region):
sect = MagicMock(spec=Sect)
sect.name = "青云门"
# 确保 headquarter.name 和 region.name 一致
sect.headquarter = MagicMock()
sect.headquarter.name = sect_region.name
return sect
def test_can_start_basic(self, healing_avatar):
"""测试基本启动条件HP不满即可"""
# Action 类通常需要 (avatar, world) 参数
action = SelfHeal(healing_avatar, healing_avatar.world)
can, reason = action.can_start()
assert can is True
assert reason == ""
def test_cannot_start_full_hp(self, healing_avatar):
"""测试满血不能启动"""
healing_avatar.hp.cur = 100
action = SelfHeal(healing_avatar, healing_avatar.world)
can, reason = action.can_start()
assert can is False
assert "HP已满" in reason
def test_execute_in_wild_no_bonus(self, healing_avatar, normal_region):
"""测试在野外非宗门的基础回复10%"""
# 设置位置
healing_avatar.tile = Tile(0, 0, TileType.PLAIN)
healing_avatar.tile.region = normal_region
healing_avatar.sect = None # 散修
# Mock effects 为空
with patch.object(type(healing_avatar), 'effects', new_callable=lambda: {}) as mock_effects:
action = SelfHeal(healing_avatar, healing_avatar.world)
action._execute()
# 预期:基础回复 10% * 100 = 10
# 初始 50 -> 60
assert healing_avatar.hp.cur == 60
assert action._healed_total == 10
def test_execute_in_wild_with_persona_bonus(self, healing_avatar, normal_region):
"""测试在野外带有 '' 特质加成(+50% efficiency"""
# 设置位置
healing_avatar.tile = Tile(0, 0, TileType.PLAIN)
healing_avatar.tile.region = normal_region
# Mock effects 带有加成
with patch.object(type(healing_avatar), 'effects', new_callable=lambda: {"extra_self_heal_efficiency": 0.5}):
action = SelfHeal(healing_avatar, healing_avatar.world)
action._execute()
# 预期:基础 0.1 * (1 + 0.5) = 0.15
# 回复 15 点 -> 50 + 15 = 65
assert healing_avatar.hp.cur == 65
assert action._healed_total == 15
def test_execute_in_sect_hq_as_member(self, healing_avatar, sect_region, mock_sect):
"""测试宗门弟子在总部回复(直接回满)"""
# 设置位置
# TileType.SECT 可能不存在,检查源码通常用 TileType.CITY 或 PLAIN关键是 region
# 如果需要区分 TileType请检查 src/classes/tile.py这里先用 PLAIN 并确保 region 是 SectRegion
# 不过为了保险,我们可以查看 TileType 定义。
# 暂时用 PLAIN关键是 region 类型。
healing_avatar.tile = Tile(0, 0, TileType.PLAIN)
healing_avatar.tile.region = sect_region
# 设置宗门身份
healing_avatar.sect = mock_sect
with patch.object(type(healing_avatar), 'effects', new_callable=lambda: {}):
action = SelfHeal(healing_avatar, healing_avatar.world)
action._execute()
# 预期:直接回满 -> 100
assert healing_avatar.hp.cur == 100
assert action._healed_total == 50
def test_execute_in_sect_hq_not_member(self, healing_avatar, sect_region):
"""测试非本门弟子在某宗门总部(视为普通区域回复)"""
# 设置位置
healing_avatar.tile = Tile(0, 0, TileType.PLAIN)
healing_avatar.tile.region = sect_region
# 散修(或无匹配宗门)
healing_avatar.sect = None
with patch.object(type(healing_avatar), 'effects', new_callable=lambda: {}):
action = SelfHeal(healing_avatar, healing_avatar.world)
action._execute()
# 预期:基础回复 10% = 10
assert healing_avatar.hp.cur == 60
assert action._healed_total == 10
def test_heal_overflow_clamp(self, healing_avatar, normal_region):
"""测试回复溢出处理(不超过 MaxHP"""
healing_avatar.hp.cur = 95 # 只差5点
healing_avatar.tile = Tile(0, 0, TileType.PLAIN)
healing_avatar.tile.region = normal_region
with patch.object(type(healing_avatar), 'effects', new_callable=lambda: {}):
action = SelfHeal(healing_avatar, healing_avatar.world)
action._execute()
# 预期:基础回复 10点但只缺5点 -> 回复5点当前100
assert healing_avatar.hp.cur == 100
assert action._healed_total == 5