当前位置: 首页 > 知识库问答 >
问题:

如何从pytest注入pygame事件?

翟京
2023-03-14

如何从pytest测试模块向正在运行的pyplay注入事件?

下面是pygame的一个最小示例,它在按下J时绘制一个白色矩形,并在按下Ctrl-Q时退出游戏。

#!/usr/bin/env python
"""minimal_pygame.py"""

import pygame


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:
        # 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模块来自动测试它。我读到过,一个人可以在运行pyplay时注入事件。在这里,我读到产生允许双向通信,所以我想我必须实现某种钩子,用于从pytest模块注入的pygame.events,但它并不简单正如我所想,所以我评论了它。如果我在下取消注释测试钩子,而game_runningpyplay甚至不等待任何输入。

下面是pytest的测试模块:

#!/usr/bin/env python
"""test_minimal_pygame.py"""

import pygame
import minimal_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
    test_press_j = pygame.event.Event(pygame.KEYDOWN, {"key": pygame.K_j})
    for e in [test_press_j]:
        wrap.send(e)

共有1个答案

朱兴学
2023-03-14

PyGame可以响应自定义用户事件,而不是按键或鼠标事件。下面是一个工作代码,其中pytestpyplay发送一个用户请求,pyplay对此做出反应,并将响应发送回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作为无状态单元测试而不是集成测试的工具,使得pyplay在得到第一个响应(拆卸测试)后退出。这是不可能继续和做更多的测试和断言在当前pyplay会话。(只要尝试复制测试代码的最后两行来重新发送事件,就会失败。)pytest不是一个合适的工具,它可以向pyplay注入一系列指令,使其达到一个先决条件,然后执行一系列测试。

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

 类似资料:
  • 主要内容:事件类型,事件处理方法,处理键盘事件,处理鼠标事件事件(Event)是 Pygame 的重要模块之一,它是构建整个游戏程序的核心,比如鼠标点击、键盘敲击、游戏窗口移动、调整窗口大小、触发特定的情节、退出游戏等等,这些都可以看做是“事件”,Pygame 会接受用户产生的各种操作(或事件),这些操作随时产生,并且操作量可大可小,那么 Pygame 是如何处理这些事件的呢? 事件类型 Pygame 定义了一个专门用来处理事件的结构,即事件队列,该结构遵

  • 问题内容: 如何从用户进行pygame打印输入: 我试图让用户键入一些内容,然后pygame将其打印在屏幕上。 这是我当前的程序: 我想要这样,当用户点击Enter时,它将清空屏幕。 帮我! 问题答案: 这是一个示例脚本,可将输入切换到屏幕。它显示了如何在遍历pygame事件队列时修改字符串。每帧都将清除屏幕,并重建名称表面并使其变白。 这是要点版本

  • 我对Spring交易非常陌生。由于我的组织使用的一些代码标准,我要求在调用任何方法时加入父事务(如果存在)。 我的应用程序是一个SpringMVC应用程序,有三层 Web层(控制器类) 服务层(包含业务逻辑的服务类) DAO Layer(数据库相关查询的DAO(数据访问层)类) 现在,在服务层上的一个方法中使用了dao层的三种不同方法。我使用@transactional将此服务方法注释为事务性的。

  • 所以我正在用pygame做一个游戏,我也想用tkinter。我在tkinter窗口中嵌入了一个pygame窗口,但我似乎什么都做不了。 对于上下文,以下是完整的代码: 当我使用时,什么都不会发生。在类中使用pyplay是有效的,但是在我更复杂的游戏中,为所有变量使用self.variable似乎是不必要的。 如何在window类之外的pygame窗口中运行代码?

  • 我正在做一个简单的pygame项目,它目前有从屏幕顶部落到屏幕底部的炸弹。如果玩家击中炸弹他们就会死。到现在为止一切正常。问题是当炸弹已经经过玩家,但还没有离开屏幕时,它仍然会杀死玩家。也就是说,炸弹将会通过玩家的下部,但如果你越过,在它越过屏幕的下部之前,你将会死亡。他是我的代码: 数值如下: player.rect.x的值范围为120到500,具体取决于播放机在屏幕上的位置。(当您移动时,屏幕

  • 我正在测试一个(Eclipse 4)应用程序(我不是在谈论单元测试,而是更多的集成和系统测试)。 我有一个反复出现的问题需要解决。我必须将测试中的上下文“注入”(@inject)到被测试的类中。换句话说,我需要测试做应用程序通常做的事情。 我所做的是创建一个私有方法: 我(错误地)期望刚才在这里创建的上下文可以在测试中的一个类中使用。例如。: 肯定少了些什么!我也创建了activator(为简洁起