Lan*_*don 7 tdd unit-testing game-physics
我正在玩一个小游戏项目,因为我在TDD方面不是很有经验,所以我很乐意在一些事情上获得一些专家意见.
首先,我很早就意识到TDD似乎不适合游戏开发.看来这个问题的观点差异很大.我最初没有受过教育的意见是TDD似乎对所有游戏逻辑都有效.我认为,任何处理视频输出和声音的内容都会被抽象为可视化测试的类.
事情开始很顺利.目标是创建一个2d太空飞行游戏(小行星为那些关心的人).我为Ship类创建了一系列单元测试.像初始化,旋转这样的东西可以很容易地在一系列中测试,例如:GetRotation(),TurnRotateRightOn(),Update(1),GetRotation(),Expect_NE(rotation1,rotation2).然后我遇到了第一个问题.
我对TDD的理解是你应该写测试你认为应该如何使用这个类.我希望船能够移动,所以我写了一个基本上说的课程.GetCoordinates(),ThrustOn(),Update(1),GetCoordinates().那可以确保船在某处移动.然而,我很快意识到我必须确保船舶以正确的方向和正确的速度移动.接下来是一个75线单元测试,我基本上必须初始化旋转,检查坐标,初始化推力,更新船,获得新坐标,检查新的旋转.更重要的是,我认为没有必要在游戏中获得船的速度(只是坐标,船应该更新自己).因此,我无法直接获得速度.所以测试基本上必须重新计算速度应该是什么,所以我可以确保它与更新后得到的坐标相匹配.总而言之,这非常混乱,非常耗时,但却很有效.测试失败,测试通过等.
直到后来当我意识到我想将船的更新代码重构为抽象的"Actor"类时才这样.我意识到虽然Actor的每个子类都需要能够正确计算一个新位置,但并不是每个子类都必须以相同的方式更新它们的速度(一些碰撞,一些不碰撞,一些碰撞静态速度).现在,我基本上面临着重复和改变庞大而庞大的测试代码的前景,我不禁认为应该有更好的方法.
有没有人有任何经验来处理单元测试这种复杂的黑盒子类型的工作?看起来我基本上不得不在测试中编写完全相同的物理代码,所以我知道结果应该是什么.这真的是自我失败,而且我确信我一路上都错过了这一切.我非常感谢任何人提供的任何帮助或建议.
我建议你首先创建一个组件,在给定一系列控制输入的情况下计算位置和方向.然后该组件构成用于测试目的的"单元".该组件的测试用例将执行您可以想到的所有场景:零加速,恒定非零加速,脉冲加速命令等.如果应用程序不需要速度,则组件不会暴露任何功能与速度有关.
在生成包含在测试中的预期输出时,重要的是要高度确信这些预期结果是正确的.因此,需要最小化生成预期结果所需的代码量.特别是,如果您发现自己编写的测试脚手架几乎与测试中的组件一样复杂,那么测试中出现的错误的前景就会成为一个严重的问题.
在这种情况下,我将直接从运动方程生成测试数据.我使用Mathematica来实现这个目的,因为我可以直接输入方程式,解决它们,然后生成结果的图形和表格.这些图表让我可以看到结果,从而确信它们是可靠的.Excel/OpenOffice/Google Apps可用于相同的目的,以及像Sage这样的Mathematica的开源替代品.无论选择什么,关键的问题是能够解决运动方程而无需编写非平凡的代码.
一旦我们有一组好的测试用例以及预期的结果,我们就可以对单元测试进行编码.请注意,测试代码非常简单,本身不执行任何计算.它只是将组件的输出与我们之前获得的硬编码结果进行比较.在测试用例到位后,我们可以编写组件本身,添加代码直到测试全部通过.当然,在严格的TDD中,这些动作恰好按此顺序发生.我承认我并没有亲自坚持瀑布,而是倾向于在创建测试数据,编写测试和编写组件代码之间来回反弹.
Mathematica或Excel文档本身在初始创建测试之后具有使用寿命.添加新功能时可以再次使用它们,或者(天堂禁止)以后可以找到错误.我主张像源代码那样对待文档.
在本练习结束时,结果是一个"防弹"组件,我们确信自己将在任何给定的控制输入集合下计算对象的正确位置和方向.在此基础上,我们可以构建使用该功能的其他组件,如船只,小行星,碟子和镜头.为了避免每个组件的测试用例组合爆炸,我将偏离严格的黑盒测试方法.因此,例如,如果我们测试"船"组件,我们会编写测试,知道它使用位置/方向组件.使用这种白盒知识,我们可以避免重新测试与运动相关的所有角落情况.船舶单元测试可以执行"烟雾测试",以验证船舶实际上是否响应控制输入,但主要重点是测试船舶部件本身特有的任何功能.
所以,总结一下:
| 归档时间: |
|
| 查看次数: |
851 次 |
| 最近记录: |