平衡设计原则:unit testing

我正在写一个Bananagrams的模拟。 目前,我有一个GameMaster类,可以维护常见的碎片集合。 deal(Player)方法向该玩家交易一定数量的棋子。

我想为此编写unit testing。 但是,此时,我没有getter,因此无法检查对象的状态。

为什么不添加吸气剂? 我不想仅为测试添加代码到公共接口。 目前,没有其他理由公开这些function。

我该怎么办? 无论如何添加getter,混乱公共API(或希望将来需要它们)? 放弃unit testing? (听起来不错。)

或者,这是否表明我的公共界面存在缺陷?

而不是依赖于播放器的具体实例,将unit testing写入接口(或等效的),并依靠模拟或其他交互来validation播放器是否处于正确的状态,而只是validation正确的调用(从GameMaster类的角度来看。

如果您无法在不依赖于validation播放器的最终状态的情况下validationGameMaster类的正确行为,那么这表明您的职责是错误的。 GameMaster应该负责告诉玩家发生了什么 ,而玩家应该负责采取适当的行动。

这也是一个好处,因为它意味着GameMaster的测试将仅依赖于GameMaster类的行为,并且如果Player类改变其行为则不需要触及。

避免为unit testing添加吸气剂。 当您想要添加一个getter时,请改为使用交互测试(如我刚才所述)而不是基于状态的测试。

有多种方法可以validation一段代码是否有效。 我们大多数人想到的第一个是基于状态的测试(即,使用getter来validation对象的最终状态是否是您认为应该的状态)。 但是,另一种validation代码是否有效的方法是使用行为或基于交互的测试。

Martin fowler在这里有一篇关于差异的文章

您应该使用这些状态保持变量测试内部function。 如果没有公共function使用它们,那么它们就是死代码。

我会说你的课程可能做得太多了。 听起来你有他们存储状态和做其他事情。

考虑什么会使它们更容易测试。 如果将状态和逻辑分开,如何测试它们? 而不是只是打电话

 GameMaster gameMaster = new GameMaster; playerOne.Score = gameMaster.ComputePlayerScore(newScore); 

你将GameState的状态实例传递给GameMaster例程的构造函数:

 GameState gameState = new GameState; GameMaster gameMaster = new GameMaster(gameState); playerOne.Score = gameMaster.ComputePlayerScore(newScore); 

然后,您的unit testing例程可以传递gameState和newScore所需的任何数据,并在返回后检查gameState中的结果。 dependency injection是你的朋友。

您可以做的一件事是将您的主类子类化为提供测试的getter。 如果您有可以使用的接口,这将更容易。

提供getter的子类化是一个半危险的命题。 如果您只是为内部属性提供getter,那么损坏将是最小的,但是您需要小心测试实际的类而不是派生的版本。

我认为专门为可测试性添加代码没有错。 unit testing对回归测试非常有用。

但是,它也不应该影响您的公共API。 因此,我建议将getters包保护,并将您的unit testing放在与Player类相同的包中。 (但在不同的源文件夹中,您可以在生产代码和测试代码之间进行清晰的分离。)

unit testing不会使您的代码更好 ,随着时间的推移,它们可以使您的整个应用程序更加稳定,并且具有更 这就是为什么如果你的GameMaster类中没有公共getter,你不需要为unit testing创​​建它们。

没有getter并不意味着你的界面是流动的,测试驱动的开发概念是写最小代码来传递一个测试(来自一个需求),如果你没有needem你不写。 unit testing消失后,打印,跟踪,日志将会在这里很长时间(好的,它们也会留在这里,但在许多情况下过度使用和过度使用)

我该怎么办? 无论如何添加getter,混乱公共API(或希望将来需要它们)?

我没有得到这个回应。 一个吸气鬼如何“混乱”?

你在做测试驱动开发。 设计是由测试一切的绝对需要驱动的。

吸气剂不是“杂乱无章”。 他们是你测试的方式。

“放弃unit testing?”

我不认为这是个好主意。