433 lines
14 KiB
Python
433 lines
14 KiB
Python
"""
|
|
Engine 单元测试
|
|
测试游戏引擎核心组件
|
|
"""
|
|
import unittest
|
|
import sys
|
|
import os
|
|
|
|
# 添加当前目录到路径
|
|
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
|
|
|
from engine import Player, HumanPlayer, AIPlayer, RoomManager, Room
|
|
from engine.game_base import GameBase, GameState, GamePhase
|
|
from engine.test_game import TestGame
|
|
|
|
|
|
class TestPlayer(unittest.TestCase):
|
|
"""测试 Player 类"""
|
|
|
|
def test_human_player_creation(self):
|
|
"""测试创建人类玩家"""
|
|
player = HumanPlayer("测试玩家", "player_001")
|
|
|
|
self.assertEqual(player.id, "player_001")
|
|
self.assertEqual(player.name, "测试玩家")
|
|
self.assertFalse(player.is_ai)
|
|
self.assertIsNone(player.room_id)
|
|
self.assertIsNone(player.seat_number)
|
|
|
|
def test_ai_player_creation(self):
|
|
"""测试创建 AI 玩家"""
|
|
player = AIPlayer("AI-1", "rule", {"difficulty": "easy"})
|
|
|
|
self.assertEqual(player.name, "AI-1")
|
|
self.assertTrue(player.is_ai)
|
|
self.assertEqual(player.ai_type, "rule")
|
|
self.assertTrue(player.is_ready) # AI 自动准备
|
|
|
|
def test_player_connect(self):
|
|
"""测试玩家连接"""
|
|
player = HumanPlayer("测试玩家")
|
|
player.connect("socket_123")
|
|
|
|
self.assertEqual(player.socket_id, "socket_123")
|
|
self.assertTrue(player.is_connected)
|
|
self.assertIsNotNone(player.connected_at)
|
|
|
|
def test_player_join_room(self):
|
|
"""测试玩家加入房间"""
|
|
player = HumanPlayer("测试玩家", "player_001")
|
|
player.join_room("room_001", 0)
|
|
|
|
self.assertEqual(player.room_id, "room_001")
|
|
self.assertEqual(player.seat_number, 0)
|
|
|
|
def test_player_leave_room(self):
|
|
"""测试玩家离开房间"""
|
|
player = HumanPlayer("测试玩家", "player_001")
|
|
player.join_room("room_001", 0)
|
|
player.leave_room()
|
|
|
|
self.assertIsNone(player.room_id)
|
|
self.assertIsNone(player.seat_number)
|
|
|
|
def test_player_to_dict(self):
|
|
"""测试玩家序列化"""
|
|
player = HumanPlayer("测试玩家", "player_001")
|
|
player.join_room("room_001", 0)
|
|
player.set_ready(True)
|
|
|
|
data = player.to_dict()
|
|
self.assertEqual(data['id'], "player_001")
|
|
self.assertEqual(data['name'], "测试玩家")
|
|
self.assertEqual(data['seat_number'], 0)
|
|
self.assertTrue(data['is_ready'])
|
|
|
|
# 测试包含私有信息
|
|
data_private = player.to_dict(include_private=True)
|
|
self.assertEqual(data_private['room_id'], "room_001")
|
|
|
|
|
|
class TestRoom(unittest.TestCase):
|
|
"""测试 Room 类"""
|
|
|
|
def test_room_creation(self):
|
|
"""测试创建房间"""
|
|
room = Room("room_001", "ABC123", "test_game", 3)
|
|
|
|
self.assertEqual(room.id, "room_001")
|
|
self.assertEqual(room.code, "ABC123")
|
|
self.assertEqual(room.game_type, "test_game")
|
|
self.assertEqual(room.max_players, 3)
|
|
self.assertEqual(room.status, "waiting")
|
|
|
|
def test_add_player(self):
|
|
"""测试添加玩家"""
|
|
room = Room("room_001", "ABC123", "test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
result = room.add_player(player)
|
|
|
|
self.assertTrue(result)
|
|
self.assertEqual(room.player_count, 1)
|
|
self.assertEqual(player.seat_number, 0)
|
|
self.assertEqual(room.host_id, "player_001")
|
|
|
|
def test_room_full(self):
|
|
"""测试房间满了"""
|
|
room = Room("room_001", "ABC123", "test_game", 2)
|
|
|
|
player1 = HumanPlayer("玩家1", "player_001")
|
|
player2 = HumanPlayer("玩家2", "player_002")
|
|
player3 = HumanPlayer("玩家3", "player_003")
|
|
|
|
room.add_player(player1)
|
|
room.add_player(player2)
|
|
|
|
self.assertTrue(room.is_full)
|
|
self.assertFalse(room.add_player(player3))
|
|
|
|
def test_remove_player(self):
|
|
"""测试移除玩家"""
|
|
room = Room("room_001", "ABC123", "test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
room.add_player(player)
|
|
result = room.remove_player("player_001")
|
|
|
|
self.assertTrue(result)
|
|
self.assertEqual(room.player_count, 0)
|
|
self.assertIsNone(player.room_id)
|
|
|
|
def test_room_to_dict(self):
|
|
"""测试房间序列化"""
|
|
room = Room("room_001", "ABC123", "test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
room.add_player(player)
|
|
|
|
data = room.to_dict(include_game_state=False)
|
|
|
|
self.assertEqual(data['id'], "room_001")
|
|
self.assertEqual(data['code'], "ABC123")
|
|
self.assertEqual(data['player_count'], 1)
|
|
self.assertEqual(len(data['players']), 1)
|
|
|
|
|
|
class TestRoomManager(unittest.TestCase):
|
|
"""测试 RoomManager 单例"""
|
|
|
|
def setUp(self):
|
|
"""每个测试前清理"""
|
|
# 重置单例状态
|
|
RoomManager._instance = None
|
|
RoomManager._initialized = False
|
|
self.manager = RoomManager()
|
|
self.manager._game_registry['test_game'] = TestGame
|
|
|
|
def test_singleton(self):
|
|
"""测试单例模式"""
|
|
manager1 = RoomManager()
|
|
manager2 = RoomManager()
|
|
|
|
self.assertIs(manager1, manager2)
|
|
|
|
def test_create_room(self):
|
|
"""测试创建房间"""
|
|
room = self.manager.create_room("test_game", 3)
|
|
|
|
self.assertIsNotNone(room)
|
|
self.assertEqual(room.game_type, "test_game")
|
|
self.assertEqual(len(room.code), 6)
|
|
|
|
# 验证可以通过 code 获取
|
|
room2 = self.manager.get_room(room_code=room.code)
|
|
self.assertEqual(room2.id, room.id)
|
|
|
|
def test_join_room(self):
|
|
"""测试加入房间"""
|
|
room = self.manager.create_room("test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
success, message = self.manager.join_room(room.code, player)
|
|
|
|
self.assertTrue(success)
|
|
self.assertEqual(message, "加入成功")
|
|
self.assertEqual(room.player_count, 1)
|
|
|
|
def test_join_nonexistent_room(self):
|
|
"""测试加入不存在的房间"""
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
success, message = self.manager.join_room("ZZZZZZ", player)
|
|
|
|
self.assertFalse(success)
|
|
self.assertEqual(message, "房间不存在")
|
|
|
|
def test_leave_room(self):
|
|
"""测试离开房间"""
|
|
room = self.manager.create_room("test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
self.manager.join_room(room.code, player)
|
|
result = self.manager.leave_room("player_001")
|
|
|
|
self.assertTrue(result)
|
|
self.assertEqual(room.player_count, 0)
|
|
|
|
def test_start_game(self):
|
|
"""测试开始游戏"""
|
|
room = self.manager.create_room("test_game", 3)
|
|
player = HumanPlayer("玩家1", "player_001")
|
|
|
|
self.manager.join_room(room.code, player)
|
|
success, message = self.manager.start_game(room.id)
|
|
|
|
self.assertTrue(success)
|
|
self.assertEqual(room.status, "playing")
|
|
self.assertIsNotNone(room.game)
|
|
|
|
|
|
class TestTestGame(unittest.TestCase):
|
|
"""测试 TestGame 示例游戏"""
|
|
|
|
def setUp(self):
|
|
"""设置测试游戏"""
|
|
self.game = TestGame("room_001", "test_game")
|
|
self.player1 = HumanPlayer("玩家1", "player_001")
|
|
self.player2 = HumanPlayer("玩家2", "player_002")
|
|
|
|
self.game.add_player(self.player1)
|
|
self.game.add_player(self.player2)
|
|
|
|
def test_game_properties(self):
|
|
"""测试游戏属性"""
|
|
self.assertEqual(self.game.min_players, 1)
|
|
self.assertEqual(self.game.max_players, 4)
|
|
self.assertEqual(self.game.player_count, 2)
|
|
self.assertTrue(self.game.can_start())
|
|
|
|
def test_start_game(self):
|
|
"""测试开始游戏"""
|
|
self.game.start()
|
|
|
|
self.assertTrue(self.game.is_started)
|
|
self.assertEqual(self.game.state.phase, GamePhase.PLAYING)
|
|
self.assertIsNotNone(self.game.target_number)
|
|
self.assertIsNotNone(self.game.state.current_turn_player_id)
|
|
|
|
def test_guess_too_small(self):
|
|
"""测试猜测太小"""
|
|
self.game.start()
|
|
self.game.target_number = 50 # 固定目标
|
|
|
|
result = self.game.handle_action("player_001", "guess", {"number": 30})
|
|
|
|
self.assertTrue(result['success'])
|
|
self.assertEqual(result['result'], 'too_small')
|
|
self.assertIn('太小了', result['message'])
|
|
|
|
def test_guess_too_large(self):
|
|
"""测试猜测太大"""
|
|
self.game.start()
|
|
self.game.target_number = 50
|
|
|
|
result = self.game.handle_action("player_001", "guess", {"number": 70})
|
|
|
|
self.assertTrue(result['success'])
|
|
self.assertEqual(result['result'], 'too_large')
|
|
|
|
def test_guess_correct(self):
|
|
"""测试猜中"""
|
|
self.game.start()
|
|
self.game.target_number = 50
|
|
|
|
result = self.game.handle_action("player_001", "guess", {"number": 50})
|
|
|
|
self.assertTrue(result['success'])
|
|
self.assertEqual(result['result'], 'correct')
|
|
self.assertTrue(self.game.is_ended)
|
|
self.assertEqual(self.game.state.winner_id, "player_001")
|
|
|
|
def test_wrong_turn(self):
|
|
"""测试非当前玩家操作"""
|
|
self.game.start()
|
|
|
|
# 假设 player_002 不是当前回合
|
|
if self.game.state.current_turn_player_id == "player_001":
|
|
result = self.game.handle_action("player_002", "guess", {"number": 50})
|
|
self.assertFalse(result['success'])
|
|
self.assertIn('不是你的回合', result['message'])
|
|
|
|
def test_invalid_guess(self):
|
|
"""测试无效猜测"""
|
|
self.game.start()
|
|
|
|
result = self.game.handle_action("player_001", "guess", {"number": 150})
|
|
|
|
self.assertFalse(result['success'])
|
|
self.assertIn('1-100', result['message'])
|
|
|
|
def test_game_to_dict(self):
|
|
"""测试游戏序列化"""
|
|
self.game.start()
|
|
|
|
data = self.game.to_dict()
|
|
|
|
self.assertEqual(data['game_type'], 'test_game')
|
|
self.assertIn('state', data)
|
|
# 目标数字不应暴露给客户端
|
|
self.assertNotIn('target', data['state'].get('data', {}))
|
|
|
|
|
|
class TestGameState(unittest.TestCase):
|
|
"""测试 GameState 类"""
|
|
|
|
def test_state_creation(self):
|
|
"""测试状态创建"""
|
|
state = GameState("test_game", "room_001")
|
|
|
|
self.assertEqual(state.game_type, "test_game")
|
|
self.assertEqual(state.room_id, "room_001")
|
|
self.assertEqual(state.phase, GamePhase.WAITING)
|
|
self.assertEqual(state.round, 0)
|
|
|
|
def test_state_start(self):
|
|
"""测试开始状态"""
|
|
state = GameState("test_game", "room_001")
|
|
state.start()
|
|
|
|
self.assertEqual(state.phase, GamePhase.PLAYING)
|
|
self.assertEqual(state.round, 1)
|
|
self.assertIsNotNone(state.started_at)
|
|
|
|
def test_state_end(self):
|
|
"""测试结束状态"""
|
|
state = GameState("test_game", "room_001")
|
|
state.start()
|
|
state.end("player_001")
|
|
|
|
self.assertEqual(state.phase, GamePhase.ENDED)
|
|
self.assertEqual(state.winner_id, "player_001")
|
|
self.assertIsNotNone(state.ended_at)
|
|
|
|
def test_next_turn(self):
|
|
"""测试切换回合"""
|
|
state = GameState("test_game", "room_001")
|
|
state.next_turn("player_001")
|
|
|
|
self.assertEqual(state.current_turn_player_id, "player_001")
|
|
self.assertEqual(state.turn_count, 1)
|
|
|
|
def test_add_history(self):
|
|
"""测试添加历史"""
|
|
state = GameState("test_game", "room_001")
|
|
state.add_history("guess", "player_001", {"number": 50})
|
|
|
|
self.assertEqual(len(state.history), 1)
|
|
self.assertEqual(state.history[0]['action'], "guess")
|
|
|
|
|
|
class IntegrationTest(unittest.TestCase):
|
|
"""集成测试"""
|
|
|
|
def setUp(self):
|
|
"""重置单例"""
|
|
RoomManager._instance = None
|
|
RoomManager._initialized = False
|
|
self.manager = RoomManager()
|
|
self.manager._game_registry['test_game'] = TestGame
|
|
|
|
def test_full_game_flow(self):
|
|
"""测试完整游戏流程"""
|
|
# 1. 创建房间
|
|
room = self.manager.create_room("test_game", 2)
|
|
self.assertIsNotNone(room)
|
|
|
|
# 2. 玩家1加入
|
|
player1 = HumanPlayer("玩家1", "p1")
|
|
success, _ = self.manager.join_room(room.code, player1)
|
|
self.assertTrue(success)
|
|
|
|
# 3. 玩家2加入
|
|
player2 = HumanPlayer("玩家2", "p2")
|
|
success, _ = self.manager.join_room(room.code, player2)
|
|
self.assertTrue(success)
|
|
|
|
# 4. 开始游戏
|
|
success, _ = self.manager.start_game(room.id)
|
|
self.assertTrue(success)
|
|
|
|
# 5. 获取游戏
|
|
game = room.game
|
|
self.assertIsNotNone(game)
|
|
game.target_number = 50 # 固定目标便于测试
|
|
|
|
# 6. 玩家1猜测
|
|
result = game.handle_action("p1", "guess", {"number": 30})
|
|
self.assertTrue(result['success'])
|
|
|
|
# 7. 玩家2猜测(正确)
|
|
result = game.handle_action("p2", "guess", {"number": 50})
|
|
self.assertTrue(result['success'])
|
|
self.assertEqual(result['result'], 'correct')
|
|
|
|
# 8. 游戏结束
|
|
self.assertTrue(game.is_ended)
|
|
self.assertEqual(game.state.winner_id, "p2")
|
|
|
|
|
|
def run_tests():
|
|
"""运行所有测试"""
|
|
loader = unittest.TestLoader()
|
|
suite = unittest.TestSuite()
|
|
|
|
# 添加所有测试类
|
|
suite.addTests(loader.loadTestsFromTestCase(TestPlayer))
|
|
suite.addTests(loader.loadTestsFromTestCase(TestRoom))
|
|
suite.addTests(loader.loadTestsFromTestCase(TestRoomManager))
|
|
suite.addTests(loader.loadTestsFromTestCase(TestTestGame))
|
|
suite.addTests(loader.loadTestsFromTestCase(TestGameState))
|
|
suite.addTests(loader.loadTestsFromTestCase(IntegrationTest))
|
|
|
|
# 运行测试
|
|
runner = unittest.TextTestRunner(verbosity=2)
|
|
result = runner.run(suite)
|
|
|
|
return result.wasSuccessful()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
success = run_tests()
|
|
sys.exit(0 if success else 1)
|