在游戏开发环境中使用像JUnit这样的测试框架是否可行?为了使游戏更具可测试性,您可以遵循哪些设计注意事项?可以/应该测试游戏的哪些部分,应该/必须将哪些部分留给人工测试?
例如,如果将游戏循环封装在一个函数中,似乎很难进行测试。我喜欢重构一个“更新”功能,该功能需要时间增量并向前推进游戏逻辑。这提供了一些有趣的技巧,例如通过提供虚假的,较慢的时间增量来降低游戏速度的功能。
在游戏开发环境中使用像JUnit这样的测试框架是否可行?为了使游戏更具可测试性,您可以遵循哪些设计注意事项?可以/应该测试游戏的哪些部分,应该/必须将哪些部分留给人工测试?
例如,如果将游戏循环封装在一个函数中,似乎很难进行测试。我喜欢重构一个“更新”功能,该功能需要时间增量并向前推进游戏逻辑。这提供了一些有趣的技巧,例如通过提供虚假的,较慢的时间增量来降低游戏速度的功能。
Answers:
TDD的宗旨之一是在某些情况下让TDD影响您的设计。您为系统编写了一个测试,然后编写代码以使该测试通过,并使依赖关系尽可能地浅。
对我来说,在单元测试中只有两件事我没有测试:
首先,我不测试视觉元素以及外观。我测试了对象是否在更新后将放置在正确的位置,相机将在其边界范围内剔除对象,并且在移交给图形引擎之前正确执行了转换(至少是在着色器之外完成的转换) ,但是一旦它碰到了图形系统,我就会画线。我不喜欢尝试嘲笑DirectX之类的东西。
其次,我并没有真正测试游戏的主要循环功能。我测试了每个系统在经过合理的增量后都可以正常工作,并且在需要时可以正常工作。然后,我只是在游戏循环中使用正确的增量更新每个系统。实际上,我可以进行测试以显示每个系统都被调用了正确的增量,但是在许多情况下,我发现这种矫kill过正(除非您使用复杂的逻辑来获取增量,否则就不会矫over过正)。
我相信您正在寻找Noel Llopis进行过单元测试:
关于测试整个游戏循环,还有另一种技术可以防止代码中的功能退化。想法是让您的游戏通过重播系统(例如,首先记录玩家的输入,然后在不同的运行中重播它们)来玩。在重放期间,您将为每个帧生成每个对象状态的快照。状态的集合然后可以称为“黄金图像”。重构代码时,您将再次运行重播,并将每个帧的状态与黄金图像状态进行比较。如果不同,则测试失败。
尽管此技术的好处显而易见,但您需要注意以下几点:
我同意Jeff和jpaver的意见。我还想补充一点,为您的体系结构采用组件模型可以大大提高其可测试性。对于组件模型,每个组件都应该执行单个工作单元,并且应该可以独立测试(或使用有限的模拟对象)。
同样,依赖实体的游戏其他部分也应仅依赖组件的子集才能发挥作用。实际上,这意味着您通常可以模拟出一些虚假的组件以方便测试这些区域,也可以仅出于测试目的而组成部分实体。例如,您省去了渲染和输入组件,因为不需要测试物理。
最后,我会忽略您从游戏社区中的一些人那里获得的有关界面的性能建议。使用接口编写好代码,如果您遇到性能问题,可以轻松地分析,识别和重构以解决问题。Noel对接口对性能的影响或它们所增加的复杂性开销的担忧并没有使我信服。
就是说,不要过度尝试独立地测试每件事。像大多数事情一样,测试和设计也要达到适当的平衡。
我以为我将添加第二个答案,以回应OP的评论,即用户可以替换单元测试。我相信这是完全错误的,因为单元测试的目的不是确保质量。如果要进行适当的测试以确保程序的质量,则应该调查方案测试或进行大量监视。
(通过出色的监控和产品作为服务运行,确实可以对客户进行一些“测试”,但是您需要拥有一个复杂的系统,该系统可以快速检测到错误并回滚负责的更改。对于一个小型开发团队。)
单元测试的主要好处是,它们迫使开发人员编写更好的设计代码。测试行为对开发人员提出了挑战,要求他们将关注点分离并封装数据。它还鼓励开发人员使用接口和其他抽象,以便他仅测试一件事。