一支函数多个前置条件,由于逻辑代码是顺序编写的,这些条件如果分开测试,就存在第二条件测试时,就要确保让第一个条件成立(哪怕用MOCK方式都很烦),第四个条件需要前面三个条件成立,前置条件越多就越烦,如何解决这个问题。
例:玩家进入游戏世界的逻辑。
(C++的语法,我尽量简化写,大家应该看得懂)
1、如果游戏世界人数超过1000,则进入失败。
2、如果playerName未找到,也就是没有创建过该player,则进入失败。
3、如果player所在的场景之前未添加到gameWorld,则进入失败。
4、如果该player已经进入游戏世界,则进入失败。
对应的类和成员函数简略为:
class GameWorld
{
public:
bool enterPlayer(String playerName)
{
}
private:
list<Player> m_playerExists;
};
现在我要为第4条逻辑编写测试代码,即:如果该player已经进入游戏世界,则进入失败。
一种写法是:
gameWorld.enterPlayer(“jack”) ;
CPPUNIT_ASSERT( !gameWorld.enterPlayer(“jack”) );
这种写法要求第一次进入世界要能够成功,但进入世界需要满足另外三个条件。第1个条件比较容易满足,而第2条件就需要通过mock确保”jack”已经创建过,第3条件就需要再向gameWorld添加jack所在的场景。而添加场景需要去满足场景添加的条件。这样一来,这个测试的准备工作很多。很多都是之前在编写第1、2、3逻辑时都已经写过的代码。为了满足测试的独立性,我四个逻辑的测试代码是分开的,这一来就出现了重复的代码。
第二种写法:
直接访问gameWorld的私有变量m_playerExists,添加一个名为”jack”的player对象。
这种写法最简单,特别在c++下只需要让测试类成为GameWorld的friend就可以访问私有变量了。但这种做法严重破坏了类的封装,如果已存在的玩家不是以list<Player>存放,重构成以map<string ,player>存放,那么测试代码也得改。照理类内部的代码重构不应该影响到测试代码才对。
第三种写法:
为GameWorld添加一支isPlayerIn()的函数
virtual bool isPlayerIn(String playerName)
{
}
然后对gameWorld进行mock。
class GameWorldMock : public GameWorld
{
protected:
virtual bool isPlayerIn(String playerName)
{
return true;
}
};
这种写法较第二种好一些,同时也驱动extract method,但同样也存在不妥的地方。isPlayerIn在实际代码中并没有用到,应该是private的,但为了让测试代码mock,要改成是protected。当然你会说isPlayerIn开放成public都行,正好可以做为enterPlayer的后置检测条件。这里我同样有一个困惑,测试中的后置检测条件往往需要通过一些get函数来提供,但常只在测试代码中才用到,实际代码中并没人调用。类似这样的检测函数很多,如果都public了,类的接口定义就很庞大。我一直提倡类的public函数越少越好,不必要的尽量不提供,这样调用者更容易调用。
其实不只是多个前置条件会遇到这个问题,很多添加、删除功能更是会遇到这个问题。删除一个对象的逻辑,就要求完成添加的所有准备,结果添加部分的代码被重复的测试。我的项目中,很从团队成员都干脆将所有测试写在一起,从添加到中间逻辑再到删除。结果一个测试上百行,不易读,不易修护。
分享到:
相关推荐
单元测试 TDD EASYMOCK 的一般用法说明 实例
[测试驱动开发的三项修炼——走出TDD丛林].
工程与技术实践-TDD中常见的10大反模式
2020QECon全球软件质量&效能大会,工程效能变革专场刘冉做的洞见TDD-理论与实践的报告的PPT文档,分享给大家!
[测试驱动开发的三项修炼——走出TDD丛林].rar
TDD测试驱动开发,准备的资料,我自己用的,公司只能上CSDN社区
AgboTddPractica 实践TDD
华为LTE TDD系统原理培训PPT文档
TDD虽是敏捷方法的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。 TDD得基本思路就是通过测试来推动整个开发得进行,但测试驱动开发并不只是单纯的测试工作,而是把需求...
《测试驱动开发的3项修炼:走出TDD丛林》用实际案例及故事讲述了测试驱动开发(TDD)的最佳实践,从TDD为什么实践起来非常困难等最根源的问题入手,循序渐进地介绍了构筑TDD的三项修炼,涉及到未雨绸缪的单元及自动化...
Laravel开发-tdd 时分双工
GSM TDD noise 分析,但愿对GSM RF感兴趣的您有所帮助
C语言的TDD参考示例代码,主要包含了书中所参考的源代码
GSM TDD 板振说明及分析方法、解决方法总结
使用phpunit 一步一步使用tdd开发模式,减少bug数,提高项目质量
3GPP采用“求同存异”的原则进行L1E FDD和TDD的标准制定工作.将两种制式的协议实现在相同的规范中描述,并尽可能保证其协议实现相同,如遇到无法融合的差异,则仅针对差异部分进行分别描述。标准制定的这种指导思想...
极限编程+TDD开发
Test Driven: Practical TDD and Acceptance TDD for Java Developers (PDF英文版)
TDD 测试