My core problem is I have Pygame as part of my app that I'm testing. And I can't get clean tests with that. Here "clean" means without manual intervention. I have code like this:
while True:
interpreter.tick()
That tick() method is as follows:
def tick(self) -> None:
self._handle_input()
And the _handle_input() method is as follows:
def _handle_input(self) -> None:
if pygame.event.get(eventtype=pygame.QUIT):
pygame.quit()
sys.exit(0)
This is literally the only Pygame logic I have in place so far. I have pre-existing tests that put my app through its paces. Here's one:
def test_chippy8_startup_banner(capsys: pytest.CaptureFixture) -> None:
from chippy8.__main__ import main
file_path = os.path.join(os.path.dirname(__file__), "./fixtures", "BC_test.ch8")
with mock.patch.object(
sys,
"argv",
[""],
):
main([file_path])
captured = capsys.readouterr()
result = captured.out
expect(result).to(contain("ChipPy-8 (CHIP-8 Emulator and Interpreter)"))
When the test is run, this causes Pygame to startup. I have to close it manually. This was entirely failing because of the sys.exit in _handle_input(). So I changed the above slightly to be:
with pytest.raises(SystemExit), mock.patch.object(
sys,
"argv",
[""],
):
main([file_path])
Notice here that I'm saying that a SystemExit will be raised. I'm not sure if this is smart. In any event, Pygame still starts up and I have to quit it ... but the test passes.
What I don't know how to do is handle the quitting on my own so the tests don't require manual intervention. I tried adding an import pygame to the test module and then just adding a pygame.quit() to the test itself, but that doesn't actually quit Pygame. (Probably because it's not the actual same instance of Pygame, I'm guessing.)
It's also unclear if I should be using some wrapper for this to handle Pygame. (I saw this question How to inject pygame events from pytest? but it was unclear how to adapt that.) Or should I just somehow be stubbing out Pygame entirely? None of my tests will ever actually test the pygame interface itself.
Essentially I'm not sure of how to handle the above simple situation but I'm also not sure of a better rather than worse practice here.