Загрузка данных
Вот готовый набор тестов для `play` с использованием `pytest` и `unittest.mock` (мы контролируем случайный выбор компьютера через мок, чтобы проверить все комбинации детерминированно):
```python
import pytest
from unittest.mock import patch
from rock_paper_scissors import RockPaperScissors # путь к вашему классу
CHOICES = ['rock', 'paper', 'scissors']
# Все 9 комбинаций: (выбор игрока, выбор компьютера, ожидаемый результат)
ALL_COMBINATIONS = [
('rock', 'rock', 'tie'),
('rock', 'paper', 'lose'),
('rock', 'scissors', 'win'),
('paper', 'rock', 'win'),
('paper', 'paper', 'tie'),
('paper', 'scissors', 'lose'),
('scissors', 'rock', 'lose'),
('scissors', 'paper', 'win'),
('scissors', 'scissors', 'tie'),
]
class TestPlayAllCombinations:
@pytest.mark.parametrize("player, computer, expected", ALL_COMBINATIONS)
def test_all_combinations(self, player, computer, expected):
with patch.object(RockPaperScissors, '_get_computer_choice', return_value=computer):
game = RockPaperScissors()
assert game.play(player) == expected
class TestWinsAndLosses:
@pytest.mark.parametrize("player, computer", [
('rock', 'scissors'),
('paper', 'rock'),
('scissors', 'paper'),
])
def test_player_wins(self, player, computer):
with patch.object(RockPaperScissors, '_get_computer_choice', return_value=computer):
game = RockPaperScissors()
assert game.play(player) == 'win'
@pytest.mark.parametrize("player, computer", [
('rock', 'paper'),
('paper', 'scissors'),
('scissors', 'rock'),
])
def test_player_loses(self, player, computer):
with patch.object(RockPaperScissors, '_get_computer_choice', return_value=computer):
game = RockPaperScissors()
assert game.play(player) == 'lose'
class TestTies:
@pytest.mark.parametrize("choice", CHOICES)
def test_tie_when_choices_match(self, choice):
with patch.object(RockPaperScissors, '_get_computer_choice', return_value=choice):
game = RockPaperScissors()
assert game.play(choice) == 'tie'
class TestInvalidInput:
@pytest.mark.parametrize("bad_choice", [
'ROCK', # регистр
'Rock',
'камень', # не английское слово
'rockk', # опечатка
'', # пустая строка
' ',
])
def test_invalid_string_raises_value_error(self, bad_choice):
game = RockPaperScissors()
with pytest.raises(ValueError):
game.play(bad_choice)
@pytest.mark.parametrize("bad_choice", [
None,
123,
3.14,
['rock'],
{'choice': 'rock'},
True,
])
def test_non_string_raises_value_error(self, bad_choice):
game = RockPaperScissors()
with pytest.raises(ValueError):
game.play(bad_choice)
def test_invalid_choice_does_not_use_computer(self):
"""При неверном вводе компьютер вообще не должен ходить."""
game = RockPaperScissors()
with patch.object(RockPaperScissors, '_get_computer_choice') as mock_get:
with pytest.raises(ValueError):
game.play('lizard')
mock_get.assert_not_called()
class TestComputerChoice:
@pytest.mark.parametrize("mocked_choice", CHOICES)
def test_computer_choice_always_valid(self, mocked_choice):
with patch('random.choice', return_value=mocked_choice):
game = RockPaperScissors()
game.play('rock') # не должно быть исключений
def test_computer_choice_called_once(self):
with patch.object(RockPaperScissors, '_get_computer_choice') as mock_get:
mock_get.return_value = 'rock'
game = RockPaperScissors()
game.play('paper')
mock_get.assert_called_once()
```
Пояснения:
- **`patch.object(..., '_get_computer_choice')`** — предполагается, что метод, генерирующий выбор компьютера (обычно `random.choice`), вынесен в отдельный метод класса. Замените имя на ваше. Если выбор делается прямо внутри `play`, замените на `patch('random.choice', return_value=...)`.
- **`@pytest.mark.parametrize`** покрывает все 9 комбинаций игрок/компьютер одним тестом — это и все победы, и все поражения, и все ничьи.
- **Проверки ошибок**: нестроковые типы (`None`, числа, списки), пустые строки, неправильные слова и опечатки — всё должно вызывать `ValueError`.
- **Тест на регистр** (`'ROCK'`, `'Rock'`) важен: по ТЗ допустимы только строчные `'rock'`, `'paper'`, `'scissors'`, значит они должны отклоняться.
- Если в вашей реализации регистр нечувствителен (например, через `.lower()`), просто перенесите эти значения из `TestInvalidInput` в `TestPlayAllCombinations`.
Запуск: `pytest -v test_rock_paper_scissors.py`