为了账号安全,请及时绑定邮箱和手机立即绑定

如何从pytest注入pygame事件?

如何从pytest注入pygame事件?

一只名叫tom的猫 2023-05-09 15:12:09
如何从 pytest 测试模块将事件注入到正在运行的 pygame 中?以下是一个 pygame 的最小示例,它在按下时绘制一个白色矩形并在按下J时退出游戏。Ctrl-Q#!/usr/bin/env python"""minimal_pygame.py"""import pygamedef minimal_pygame(testing: bool=False):    pygame.init()    game_window_sf = pygame.display.set_mode(            size=(400, 300),         )    pygame.display.flip()    game_running = True    while game_running:        # Main game loop:        # the following hook to inject events from pytest does not work:        # if testing:            # test_input = (yield)            # pygame.event.post(test_input)        for event in pygame.event.get():            # React to closing the pygame window:            if event.type == pygame.QUIT:                game_running = False                break            # React to keypresses:            if event.type == pygame.KEYDOWN:                if event.key == pygame.K_q:                    # distinguish between Q and Ctrl-Q                    mods = pygame.key.get_mods()                    # End main loop if Ctrl-Q was pressed                    if mods & pygame.KMOD_CTRL:                        game_running = False                        break                # Draw a white square when key J is pressed:                if event.key == pygame.K_j:                    filled_rect = game_window_sf.fill(pygame.Color("white"), pygame.Rect(50, 50, 50, 50))                    pygame.display.update([filled_rect])    pygame.quit()if __name__ == "__main__":    minimal_pygame()我想写一个pytest模块来自动测试它。我读过可以将事件注入 running pygame。在这里我读到yield from允许双向通信,所以我想我必须实现某种钩子以便pygame.events从模块注入pytest,但它并不像我想的那么简单,所以我把它注释掉了。如果我取消注释 下的测试挂钩while game_running,pygame甚至不等待任何输入。这是 pytest 的测试模块:#!/usr/bin/env python"""test_minimal_pygame.py"""import pygameimport minimal_pygamedef pygame_wrapper(coro):    yield from coro
查看完整描述

1 回答

?
慕仙森

TA贡献1827条经验 获得超7个赞

Pygame 可以响应自定义用户事件,而不是按键或鼠标事件。这是一个工作代码,其中pytest将用户事件发送到pygame,pygame对其作出反应并将响应发送回pytest以进行评估:


#!/usr/bin/env python

"""minimal_pygame.py"""


import pygame



TESTEVENT = pygame.event.custom_type()



def minimal_pygame(testing: bool=False):

    pygame.init()

    game_window_sf = pygame.display.set_mode(

            size=(400, 300), 

        )

    pygame.display.flip()

    game_running = True

    while game_running:

        # Hook for testing

        if testing:

            attr_dict = (yield)

            test_event = pygame.event.Event(TESTEVENT, attr_dict)

            pygame.event.post(test_event)

        # Main game loop:

        pygame.time.wait(1000)

        for event in pygame.event.get():

            # React to closing the pygame window:

            if event.type == pygame.QUIT:

                game_running = False

                break

            # React to keypresses:

            if event.type == pygame.KEYDOWN:

                if event.key == pygame.K_q:

                    # distinguish between Q and Ctrl-Q

                    mods = pygame.key.get_mods()

                    # End main loop if Ctrl-Q was pressed

                    if mods & pygame.KMOD_CTRL:

                        game_running = False

                        break

            # React to TESTEVENTS:

            if event.type == TESTEVENT:

                if event.instruction == "draw_rectangle":

                    filled_rect = game_window_sf.fill(pygame.Color("white"), pygame.Rect(50, 50, 50, 50))

                    pygame.display.update([filled_rect])

                    pygame.time.wait(1000)

                    if testing:

                        # Yield the color value of the pixel at (50, 50) back to pytest

                        yield game_window_sf.get_at((50, 50))

    pygame.quit()



if __name__ == "__main__":

    minimal_pygame()

这是测试代码:


#!/usr/bin/env python

"""test_minimal_pygame.py"""


import minimal_pygame

import pygame



def pygame_wrapper(coro):

    yield from coro



def test_minimal_pygame():

    wrap = pygame_wrapper(minimal_pygame.minimal_pygame(testing=True))

    wrap.send(None) # prime the coroutine

    # Create a dictionary of attributes for the future TESTEVENT

    attr_dict = {"instruction": "draw_rectangle"}

    response = wrap.send(attr_dict)

    assert response == pygame.Color("white")

它有效,但是,pytest作为无状态单元测试而不是集成测试的工具,它使 pygame 在获得第一个响应(拆卸测试)后退出。不可能在当前的 pygame 会话中继续并做更多的测试和断言。(只需尝试复制测试代码的最后两行以重新发送事件,它将失败。)Pytest 不是将一系列指令注入 pygame 以使其达到前提条件然后执行一系列测试的正确工具.

至少这是我从 pygame discord 频道的人们那里听到的。对于自动化集成测试,他们建议使用像Cucumber这样的 BDD 工具(或behave for python)。



查看完整回答
反对 回复 2023-05-09
  • 1 回答
  • 0 关注
  • 83 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信