Skip to content
This repository was archived by the owner on Apr 24, 2025. It is now read-only.

Commit c973a2c

Browse files
committed
add unit tests for game, display and snake
1 parent a082507 commit c973a2c

File tree

8 files changed

+167
-4
lines changed

8 files changed

+167
-4
lines changed
File renamed without changes.

projects/Snake Game/display.py renamed to projects/Snake Game/src/display.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,3 @@ def update_ui(self, snake, food, score):
3333
score_display = self.font.render(f"Score: {score}", True, RgbColors.WHITE)
3434
self.window.blit(score_display, [0, 0]) # score in top left corner of window
3535
pygame.display.flip()
36-
37-
def clock_tick(self, speed):
38-
self.clock.tick(speed)

projects/Snake Game/game.py renamed to projects/Snake Game/src/game.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ def play_step(self):
6464
self.snake.blocks.pop()
6565
# Update UI and Clock
6666
self.display.update_ui(self.snake, self.food, self.score)
67-
self.display.clock_tick(GameSettings.SPEED)
67+
self.display.clock.tick(GameSettings.SPEED)
6868
game_over = self.is_collision()
6969
return game_over, self.score
7070

File renamed without changes.
File renamed without changes.
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import unittest
2+
from unittest.mock import patch, MagicMock
3+
import pygame
4+
import pygame.time
5+
from display import Display
6+
from constants import RgbColors, GameSettings, Point
7+
from snake import Snake
8+
9+
10+
class TestDisplay(unittest.TestCase):
11+
12+
def setUp(self):
13+
self.display = Display()
14+
self.snake = Snake()
15+
16+
@patch('pygame.init')
17+
@patch('pygame.font.Font')
18+
@patch('pygame.display.set_mode')
19+
@patch('pygame.display.set_caption')
20+
@patch('pygame.time.Clock')
21+
def test_init(self, mock_init, mock_font, mock_set_mode, mock_set_caption, mock_clock):
22+
mock_init.return_value = True
23+
mock_font_instance = MagicMock()
24+
mock_font.return_value = mock_font_instance
25+
mock_window = MagicMock()
26+
mock_set_mode.return_value = mock_window
27+
mock_clock_instance = MagicMock()
28+
mock_clock.return_value = mock_clock_instance
29+
30+
mock_set_mode.assert_called_with((GameSettings.WIDTH, GameSettings.HEIGHT))
31+
mock_set_caption.assert_called_with("Snake")
32+
mock_clock.assert_called()
33+
34+
self.assertEqual(self.display.width, GameSettings.WIDTH)
35+
self.assertEqual(self.display.height, GameSettings.HEIGHT)
36+
self.assertIsInstance(self.display.font, pygame.font.Font)
37+
self.assertIsInstance(self.display.window, MagicMock)
38+
self.assertIsInstance(self.display.clock, MagicMock)
39+
40+
@patch('pygame.init')
41+
@patch('pygame.display.set_mode')
42+
@patch('pygame.display.set_caption')
43+
@patch('pygame.font.Font')
44+
@patch('pygame.time.Clock')
45+
def test_init(self, mock_clock, mock_font, mock_set_caption, mock_set_mode, mock_init):
46+
display = Display()
47+
mock_init.assert_called_once()
48+
mock_font.assert_called_once()
49+
mock_set_caption.assert_called_with("Snake")
50+
mock_set_mode.assert_called_with((GameSettings.WIDTH, GameSettings.HEIGHT))
51+
mock_clock.assert_called_once()
52+
53+
self.assertIsInstance(display.font, MagicMock)
54+
self.assertIsInstance(display.window, MagicMock)
55+
self.assertIsInstance(display.clock, MagicMock)
56+
57+
@patch('pygame.draw.rect')
58+
@patch('pygame.font.Font')
59+
@patch('pygame.display.flip')
60+
@patch('pygame.display.set_mode')
61+
def test_update_ui(self, mock_set_mode, mock_display_flip, mock_font, mock_draw_rect):
62+
mock_window = mock_set_mode.return_value
63+
mock_font_instance = mock_font.return_value
64+
mock_font_instance.render = MagicMock()
65+
66+
self.food = Point(100, 100)
67+
self.score = 10
68+
self.display.window = mock_window
69+
self.display.font = mock_font_instance
70+
self.display.update_ui(self.snake, self.food, self.score)
71+
72+
mock_draw_rect.assert_called()
73+
mock_font_instance.render.assert_called()
74+
mock_display_flip.assert_called()
75+
76+
77+
if __name__ == '__main__':
78+
unittest.main()
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import unittest
2+
from unittest.mock import patch, MagicMock
3+
from game import Game
4+
from constants import GameSettings, Point
5+
6+
7+
class TestGame(unittest.TestCase):
8+
def setUp(self):
9+
self.game = Game()
10+
11+
def test_init(self):
12+
self.assertIsNotNone(self.game.display)
13+
self.assertIsNotNone(self.game.snake)
14+
self.assertEqual(self.game.score, 0)
15+
self.assertIsNotNone(self.game.food)
16+
17+
def test_is_collision(self):
18+
# Snake is out of bounds
19+
self.game.snake.head = Point(-1, -1)
20+
self.assertTrue(self.game.is_collision())
21+
# Snake collides with itself
22+
self.game.snake.head = self.game.snake.blocks[1]
23+
self.assertTrue(self.game.is_collision())
24+
25+
@patch('pygame.event.get')
26+
@patch('pygame.draw.rect')
27+
@patch('pygame.display.flip')
28+
@patch('pygame.font.Font')
29+
def test_play_step(self, mock_event_get, mock_draw_rect, mock_display_flip, mock_font):
30+
mock_event_get.return_value = []
31+
mock_font_instance = MagicMock()
32+
mock_font_instance.render.return_value = MagicMock()
33+
mock_font.return_value = mock_font_instance
34+
35+
init_snake_length = len(self.game.snake.blocks)
36+
init_score = self.game.score
37+
init_head_position = self.game.snake.head
38+
# Place food in front of snake
39+
self.game.food = Point(init_head_position.x + GameSettings.BLOCK_SIZE, init_head_position.y)
40+
self.game.play_step()
41+
42+
self.assertEqual(len(self.game.snake.blocks), init_snake_length + 1)
43+
self.assertEqual(self.game.score, init_score + 1)
44+
new_head_position = Point(init_head_position.x + GameSettings.BLOCK_SIZE, init_head_position.y)
45+
self.assertEqual(self.game.snake.head, new_head_position)
46+
47+
def test_place_food(self):
48+
self.game.place_food()
49+
self.assertNotIn(self.game.food, self.game.snake.blocks)
50+
51+
52+
if __name__ == '__main__':
53+
unittest.main()
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import unittest
2+
from snake import Snake, Point, Direction
3+
from constants import GameSettings
4+
5+
6+
class TestSnake(unittest.TestCase):
7+
def setUp(self):
8+
self.snake = Snake()
9+
10+
def test_init(self):
11+
self.assertEqual(self.snake.head, Point(GameSettings.WIDTH / 2, GameSettings.HEIGHT / 2))
12+
self.assertEqual(self.snake.block_size, GameSettings.BLOCK_SIZE)
13+
self.assertEqual(len(self.snake.blocks), 3)
14+
self.assertEqual(self.snake.direction, Direction.RIGHT)
15+
16+
def test_move(self):
17+
init_head = self.snake.head
18+
self.snake.move(Direction.RIGHT)
19+
new_head_position = Point(init_head.x + GameSettings.BLOCK_SIZE, init_head.y)
20+
self.assertEqual(self.snake.head, new_head_position)
21+
self.assertEqual(self.snake.blocks[0], new_head_position)
22+
23+
def test_self_collision(self):
24+
self.snake.head = Point(100, 100)
25+
self.snake.blocks = [
26+
self.snake.head,
27+
Point(80, 100),
28+
Point(60, 100),
29+
Point(100, 100)
30+
]
31+
self.assertTrue(self.snake.self_collision())
32+
33+
34+
if __name__ == '__main__':
35+
unittest.main()

0 commit comments

Comments
 (0)