Extract shared test fixtures to conftest.py

Moved common test fixtures (mock_writer, mock_reader, test_zone, player,
nearby_player, clear_state) from individual test files into a shared
conftest.py. This eliminates duplication across test_power.py, test_sleep.py,
test_combat_zaxis.py, test_quit.py, test_stamina_cues.py, and
test_stamina_cue_wiring.py.

Some test files override specific fixtures where they need custom behavior
(e.g., test_quit.py adds a close method to mock_writer, stamina tests use
smaller zones and custom player positions).
This commit is contained in:
Jared Miller 2026-02-14 00:33:07 -05:00
parent 8bb87965d7
commit be63a1cbde
Signed by: shmup
GPG key ID: 22B5C6D66A38B06C
7 changed files with 84 additions and 225 deletions

69
tests/conftest.py Normal file
View file

@ -0,0 +1,69 @@
"""Shared test fixtures for mudlib tests."""
from unittest.mock import AsyncMock, MagicMock
import pytest
from mudlib.combat.engine import active_encounters
from mudlib.player import Player, players
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear global state before and after each test."""
players.clear()
active_encounters.clear()
yield
players.clear()
active_encounters.clear()
@pytest.fixture
def mock_writer():
"""Create a mock writer for testing."""
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture
def mock_reader():
"""Create a mock reader for testing."""
return MagicMock()
@pytest.fixture
def test_zone():
"""Create a test zone for players."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
"""Create a test player named Goku at origin."""
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.fixture
def nearby_player(mock_reader, mock_writer, test_zone):
"""Create a nearby test player named Vegeta at origin."""
p = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p

View file

@ -1,67 +1,20 @@
"""Tests for z-axis altitude checks in combat.""" """Tests for z-axis altitude checks in combat."""
from pathlib import Path from pathlib import Path
from unittest.mock import AsyncMock, MagicMock
import pytest import pytest
from mudlib.combat import commands as combat_commands from mudlib.combat import commands as combat_commands
from mudlib.combat.encounter import CombatState from mudlib.combat.encounter import CombatState
from mudlib.combat.engine import active_encounters, get_encounter, start_encounter from mudlib.combat.engine import get_encounter, start_encounter
from mudlib.combat.moves import load_moves from mudlib.combat.moves import load_moves
from mudlib.player import Player, players
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear encounters and players before and after each test."""
active_encounters.clear()
players.clear()
yield
active_encounters.clear()
players.clear()
@pytest.fixture
def test_zone():
"""Create a test zone for players."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.fixture @pytest.fixture
def target(mock_reader, mock_writer, test_zone): def target(mock_reader, mock_writer, test_zone):
"""Alias for nearby_player fixture with name 'target' for this module."""
from mudlib.player import Player, players
t = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer) t = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer)
t.location = test_zone t.location = test_zone
test_zone._contents.append(t) test_zone._contents.append(t)

View file

@ -2,71 +2,12 @@
import asyncio import asyncio
import time import time
from unittest.mock import AsyncMock, MagicMock
import pytest import pytest
from mudlib.combat.encounter import CombatEncounter from mudlib.combat.encounter import CombatEncounter
from mudlib.combat.engine import active_encounters from mudlib.combat.engine import active_encounters
from mudlib.commands.power import cmd_power from mudlib.commands.power import cmd_power
from mudlib.player import Player, players
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear players and encounters before and after each test."""
players.clear()
active_encounters.clear()
yield
players.clear()
active_encounters.clear()
@pytest.fixture
def test_zone():
"""Create a test zone for players."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.fixture
def nearby_player(mock_reader, mock_writer, test_zone):
p = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.mark.asyncio @pytest.mark.asyncio

View file

@ -1,39 +1,18 @@
"""Tests for quit command.""" """Tests for quit command."""
from unittest.mock import AsyncMock, MagicMock, patch from unittest.mock import MagicMock, patch
import pytest import pytest
from mudlib.commands.quit import cmd_quit from mudlib.commands.quit import cmd_quit
from mudlib.player import Player, players from mudlib.player import players
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear players before and after each test."""
players.clear()
yield
players.clear()
@pytest.fixture
def test_zone():
"""Create a test zone for players."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture @pytest.fixture
def mock_writer(): def mock_writer():
"""Override conftest mock_writer to add close method for quit tests."""
from unittest.mock import AsyncMock
writer = MagicMock() writer = MagicMock()
writer.write = MagicMock() writer.write = MagicMock()
writer.drain = AsyncMock() writer.drain = AsyncMock()
@ -41,20 +20,6 @@ def mock_writer():
return writer return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_quit_blocked_during_combat(player): async def test_quit_blocked_during_combat(player):
"""Test quit is blocked when player is in combat mode.""" """Test quit is blocked when player is in combat mode."""

View file

@ -1,67 +1,9 @@
"""Tests for sleep command.""" """Tests for sleep command."""
from unittest.mock import AsyncMock, MagicMock
import pytest import pytest
from mudlib.commands.sleep import cmd_sleep from mudlib.commands.sleep import cmd_sleep
from mudlib.player import Player, players
from mudlib.resting import STAMINA_PER_TICK, process_resting from mudlib.resting import STAMINA_PER_TICK, process_resting
from mudlib.zone import Zone
@pytest.fixture(autouse=True)
def clear_state():
"""Clear players before and after each test."""
players.clear()
yield
players.clear()
@pytest.fixture
def test_zone():
"""Create a test zone for players."""
terrain = [["." for _ in range(256)] for _ in range(256)]
zone = Zone(
name="testzone",
width=256,
height=256,
toroidal=True,
terrain=terrain,
impassable=set(),
)
return zone
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture
def mock_reader():
return MagicMock()
@pytest.fixture
def player(mock_reader, mock_writer, test_zone):
p = Player(name="Goku", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.fixture
def nearby_player(mock_reader, mock_writer, test_zone):
p = Player(name="Vegeta", x=0, y=0, reader=mock_reader, writer=mock_writer)
p.location = test_zone
test_zone._contents.append(p)
players[p.name] = p
return p
@pytest.mark.asyncio @pytest.mark.asyncio

View file

@ -10,21 +10,15 @@ from mudlib.player import Player
from mudlib.zone import Zone from mudlib.zone import Zone
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture @pytest.fixture
def test_zone(): def test_zone():
"""Override conftest test_zone with smaller zone for stamina tests."""
return Zone(name="test", width=10, height=10) return Zone(name="test", width=10, height=10)
@pytest.fixture @pytest.fixture
def player(mock_writer, test_zone): def player(mock_writer, test_zone):
"""Override conftest player with custom position and stats for stamina tests."""
p = Player( p = Player(
name="Goku", name="Goku",
x=5, x=5,
@ -40,6 +34,7 @@ def player(mock_writer, test_zone):
@pytest.fixture @pytest.fixture
def defender(test_zone): def defender(test_zone):
"""Defender fixture with custom position for stamina tests."""
w = MagicMock() w = MagicMock()
w.write = MagicMock() w.write = MagicMock()
w.drain = AsyncMock() w.drain = AsyncMock()

View file

@ -8,21 +8,15 @@ from mudlib.player import Player
from mudlib.zone import Zone from mudlib.zone import Zone
@pytest.fixture
def mock_writer():
writer = MagicMock()
writer.write = MagicMock()
writer.drain = AsyncMock()
return writer
@pytest.fixture @pytest.fixture
def test_zone(): def test_zone():
"""Override conftest test_zone with smaller zone for stamina tests."""
return Zone(name="test", width=10, height=10) return Zone(name="test", width=10, height=10)
@pytest.fixture @pytest.fixture
def player(mock_writer, test_zone): def player(mock_writer, test_zone):
"""Override conftest player with custom position and stats for stamina tests."""
p = Player( p = Player(
name="Goku", name="Goku",
x=5, x=5,
@ -38,7 +32,7 @@ def player(mock_writer, test_zone):
@pytest.fixture @pytest.fixture
def nearby_player(test_zone): def nearby_player(test_zone):
"""A nearby player to receive broadcasts.""" """Override conftest nearby_player with custom position for stamina tests."""
w = MagicMock() w = MagicMock()
w.write = MagicMock() w.write = MagicMock()
w.drain = AsyncMock() w.drain = AsyncMock()