Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / iPhone

C++ on the iPhone: Test Driven Development

2.50/5 (3 votes)
2 Jun 2009CPOL4 min read 19.2K  
I have been learning quite a few development strategies as of late, and the newest one that I’ve taken a peek into is Test Driven Development (TDD), or Unit Testing.

I have been learning quite a few development strategies as of late, and the newest one that I’ve taken a peek into is Test Driven Development (TDD), or Unit Testing. The idea behind TDD and Unit Testing is to split up your problems into small, easily manageable problems rather than having to design everything from the get go, and living with any or all of your mistakes for the rest of the project. TDD is a very complex topic and usually requires the use of various frameworks for dynamic unit tests, but I’ll be focusing on the ‘beginning’ method of TDD, static unit tests.

How do we start? Well in my current engine, what I did was write a class called “TestGame.cpp” which was a singleton class that housed various methods for testing the game. In that class, I would write functions to test a particular class I would be creating, or an entire game loop to test the logic of a class without having to construct a game world for our object to live in. Inside the TestGame class there is a function called ’startTesting()’ which will call anything you wish to test. Lets write a sample test to give you an idea on the very basics of what I’m doing.

C++
//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 );
}

Now if I were to compile this code, it would spit out a bunch of errors. “Set Name? .. Get Identity? I don’t know how to do that!” and that’s the point! These functions have not been written yet. The basic idea is to construct what you want your actor class to do, and then write the code to DO it. The next step is to write JUST enough code to get the project to compile, so… to the actor class we go! Quite literally, all we’ll be doing in the next step is to write the skeleton functions like such (NOTE: The various helper classes like Vector2 have been written and added to the engine, they are already created and have already been tested using this approach and do not come ’standard’ in C++ (or Obj-C as far as I know);

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;
C++
//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 )
{
}

This code should now compile and run, even though it doesn’t do anything. Well we know what we want to do, and we now have a skeleton to do it… so we should get going on writing the code!

For example, we know that we want the identity of the actor to be unique, and that the setIdentity function should only set the string if it currently does not have an identity so since this is going to be the most difficult function to write, let's do that one real quick.

C++
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;
}

Really, that's it. The actor doesn’t know if its identity is unique, nor does it know how to obtain a unique identity. It just says “Okay, I don’t have an identity right now, so I’ll take this one and make it my own!” The idea is the actor class exists on its own, and functions as its own data. To obtain a unique identity and to keep track of all actors in the game world, we will use an ActorController (remember that pesky thing called the Model / View / Controller? ) The Actor class is the data (model) while the Controller will manage that data and when needed, present it to the view for rendering.. but that is a topic for another post.

The last thing we should do is COMMENT COMMENT COMMENT! I am a big fan of commenting my code, and documenting not only what the function does but why its implemented the way it is. If you ever look over your code 3 months down the line, you’ll say to yourself “I didn’t write this… what was I thinking?!” … well if you commented your code, you’d know! its a good habit to get into, and if you look at my Screen Controller from a few posts back, you’ll notice just how much I comment.

So that is all for today. Test Driven Development is a HUGE area, and this is just the very very basics of how it can be done. Once you get into the frameworks, it can be pretty complex, but very much worth the effort.

Happy coding everyone!

Read original blog post here

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)