iPhone 上的 C++: 测试驱动开发






2.50/5 (3投票s)
最近我一直在学习一些开发策略,而我最近关注的一个新策略是测试驱动开发 (TDD) 或单元测试。
最近我一直在学习一些开发策略,而我最近关注的一个新策略是测试驱动开发 (TDD) 或单元测试。TDD 和单元测试背后的思想是将问题分解成小的、易于管理的问题,而不是一开始就设计所有的东西,并且在项目的剩余时间里忍受任何或所有的错误。TDD 是一个非常复杂的主题,通常需要使用各种框架进行动态单元测试,但我将专注于 TDD 的“开始”方法,静态单元测试。
我们如何开始?好吧,在我当前的引擎中,我所做的是编写一个名为“TestGame.cpp”的类,它是一个单例类,包含用于测试游戏的各种方法。在该类中,我会编写函数来测试我将要创建的特定类,或者测试整个游戏循环来测试类的逻辑,而无需为我们的对象构建一个游戏世界。在 TestGame
类中有一个名为 'startTesting()
' 的函数,它将调用任何您希望测试的内容。让我们编写一个示例测试,让您了解我正在做的最基本的内容。
//This function is public, and able to be called when you obtain the instance
//of the TestGame class. We will start every test from this function, and keep
//it kind of like a list. Whenever an aspect needs to be changed, for example
//with the actor class, we can simply uncomment the 'testActorClass()' line
//to ensure it still passes all of our tests.
void TestGame startTesting()
{
testActorClass();
}
//This function, however... is private and unable to be called by anything
//outside the "TestGame" class, and should only be called by the 'startTesting()'
//function.
void testActorClass()
{
Actor *act = new Actor();
string testString;
float testFloat;
act->setAlpha( .50f );
testFloat = act->getAlpha();
// identities are unique and assigned when the object
/// is constructed.. Calling this function
// should not change the identity
act->setIdentity( "newIdentity" );
testString = act->getIdentity(); //should still be "Actor_#"
act->setName( "Werewolf ");
testString = act->getName();//should be "Werewolf"
act->setPosition( Vector2::ZERO() );
testString = act->getPosition();//should be 0,0
act->setSize( Vector2(32, 32) );
testString = act->getSize();//should be 32, 32
act->update( .003f );
}
现在,如果我编译这段代码,它会抛出一堆错误。“设置名字?.. 获取身份?我不知道怎么做!” 这就是重点!这些函数尚未编写。基本思想是构建您希望 actor 类执行的操作,然后编写代码来执行它。下一步是编写 JUST 足够的代码来使项目能够编译,所以…我们去 actor 类!毫不夸张地说,我们在下一步将要做的就是编写像这样的骨架函数(注意:像 Vector2
这样的各种辅助类已经编写并添加到引擎中,它们已经创建并且已经使用这种方法进行了测试,并且在 C++(或据我所知 Obj-C)中不是“标准”的);
//in the Actor.h file
public:
bool setIdentity( const string &value );
string getIdentity() const { return identity; }
bool setName( const string &value );
string getName() const { return name; }
bool setPosition( const Vector2 &value );
Vector2* getPosition() { return position; }
bool setSize( const Vector2 &value );
Vector2* getSize() const { return size; }
bool setAlpha( const float value );
float getAlpha() const { return alpha; }
virtual void update( const float deltaTime );
protected:
string identity;
string name;
Vector2 *position;
Vector2 *size;
float alpha;
//in the Actor.cpp file
bool Actor::setIdentity( const string &value )
{
}
bool Actor::setName( const string &value )
{
}
bool Actor::setPosition( const Vector2 &value )
{
}
bool Actor::setSize( const Vector2 &value )
{
}
bool Actor::setAlpha( const float value )
{
}
void Actor::update( const float deltaTime )
{
}
这段代码现在应该可以编译和运行,即使它什么也不做。好吧,我们知道我们想要做什么,并且我们现在有一个骨架来做它……所以我们应该开始编写代码!
例如,我们知道我们希望 actor 的身份是唯一的,并且 setIdentity 函数应该只在当前没有身份的情况下设置字符串,所以因为这将是最难编写的函数,让我们快速完成它。
bool Actor::setIdentity( const string &value )
{
// if the identity has already been set, do not
// re-set the identity. Object must be destroyed
// and re-created to reset an identity.
if ( identity.length() != 0)
{
return false;
}
// if the identity has not been set, set it
// and return true
identity = value;
return true;
}
真的,就是这样。actor 不知道它的身份是否唯一,也不知道如何获得唯一的身份。它只是说“好的,我现在没有身份,所以我将接受这个并使其成为我自己的!” 想法是 actor 类独立存在,并作为自己的数据。为了获得唯一的身份并跟踪游戏世界中的所有 actor,我们将使用一个 ActorController
(还记得那个讨厌的叫做 Model / View / Controller 的东西吗?)。Actor
类是数据(模型),而 Controller 将管理该数据并在需要时将其呈现给视图进行渲染……但这将是另一篇文章的主题。
我们应该做的最后一件事是注释注释注释!我非常喜欢注释我的代码,并记录不仅函数的作用,还要记录它为什么以这种方式实现。如果你在 3 个月后回顾你的代码,你会对自己说“我没有写这个……我在想什么?!” ……好吧,如果你注释了你的代码,你就会知道!这是一个养成的好习惯,如果你看看我之前的一些帖子中的屏幕控制器,你会注意到我注释了多少。
今天就到此为止。测试驱动开发是一个巨大的领域,这只是如何完成它的非常非常基础的内容。一旦你进入框架,它可能会非常复杂,但非常值得付出努力。
祝大家编码愉快!
在此处阅读原始博客文章 这里