Wednesday, November 4, 2009

EXAMPLE









































Prev don't be afraid of buying books Next






























EXAMPLE





Test 1: An empty list should have a
size of zero.



We'll start with the test for an empty list:




class TestEmptyMovieList : public CppUnit::TestCase {
private:
MovieList *theList;

public:
TestEmptyMovieList(std::string name);
virtual void registerTests(TestSuite *suite);
void setUp();
void testSize();
};

TestEmptyMovieList::TestEmptyMovieList(std::string name)
:CppUnit::TestCase(name)
{
}

void TestEmptyMovieList::registerTests(TestSuite *suite)
{
suite
->
addTest(new TestCaller
<
TestEmptyMovieList
>
(
"testSize",
&TestEmptyMovieList::testSize,
*this));
}

void TestEmptyMovieList::setUp()
{
theList=new MovieList();
}

void TestEmptyMovieList::testSize()
{
CPPUNIT ASSERT EQUAL MESSAGE("Empty list should be empty",
0,
emptyList
->
size());
}






Here's the stub we need to compile:




class MovieList
public:
MovieList();
int size();
};

MovieList::MovieList() {
}





int MovieList::size() {
return 0;
}






This passes because our stub implementation of
MovieList::size() returns 0 to keep the compiler
happy.





Test 2: Adding a movie to an empty
list should result in a list with a size of one.



This test will add a movie and verify that the
size is now 1. As in earlier chapters, we'll move to a new
fixture for this:




class TestOneItemList : public CppUnit::TestCase {
private:
MovieList *theList;

public:
TestOneItemList(std::string name);
virtual void registerTests(TestSuite *suite);
void setUp();
void testSize();
};

TestOneItemList::TestOneItemList(std::string name)
:CppUnit::TestCase(name)
{
}

void TestOneItemList::registerTests(TestSuite *suite)
{
suite
->
addTest(new TestCaller
<
TestOneItemList
>
("testSize",
&TestOneItemList::testSize,
*this));
}

void TestOneItemList::setUp()
{
theList = new MovieList();
Movie starWars("Star Wars");
theList
->
add(starWars);
}

void TestOneItemList::testSize()
{
CPPUNIT ASSERT EQUAL MESSAGE("One item list should have one item",
1,
theList
->
size());
}






This requires that we create a stub
Movie class:




class Movie {
public:
Movie(std::string aName);
};





Movie::Movie(std::string aName)
{
}






We also need to stub an add method for
MovieList:




void MovieList::add(Movie movie)
{
}






This now compiles and fails with:




.F

!!!FAILURES!!!
Test Results:
Run: 1 Failures: 1 Errors: 0

1) test: testSize (F) line: 27 TestOneItemList.cpp
expected: 1
but was: 0
additional message:
One item list should have one item






Now we can fake it one step better by counting
the number of movies that are added:




class MovieList {
private:
int numberOfMovies;

public:
MovieList();
int size();
void add(Movie aMovie);
};

MovieList::MovieList() {
numberOfMovies = 0;
}

int MovieList::size() {
return numberOfMovies;
}

void MovieList::add(Movie movie)
{
numberOfMovies++;
}







Our tests pass and there isn't anything in
MovieList to clean up.





Test 3: If we add a movie to a list,
we should be able to ask if it's there and receive a positive
response.



Our next test should verify that the movie that
was added is really there; again, we'll fake it at first:




void TestOneItemList::testContains()
{
CPPUNIT ASSERT MESSAGE("Star Wars should be in the list.",
the List
->
containsMovieNamed("Star Wars"));
}






We next need a stub containsMovieNamed
method in MovieList that fakes it for the purposes of this
test:




bool MovieList::containsMovieNamed(std::string name)
{
return true;
}








Test 4: Asking about the presence of a
movie that wasn't added should result in a negative response.



Now we need to test that a movie that we didn't
add is, in fact, not reported as being in the list:




void TestOneItemList::testDoesNotContain()
{
CPPUNIT ASSERT MESSAGE("Star Trek should not be in the list.",
!theList
->
containsMovieNamed("Star Trek"));
}






This, of course, fails with:




...F

!!!FAILURES!!!
Test Results:
Run: 3 Failures: 1 Errors: 0

1) test: testDoesNotContain (F) line: 39 TestOneItemList.cpp
"Star Trek should not be in the list."






This test drives us to move from fake to make in
terms of keeping track of what movies have been added to the
list:




class MovieList {
private:
int numberOfMovies;
map
<
std::string, Movie
>
movies;
public:
MovieList();
int size();
void add(Movie aMovie);
bool containsMovieNamed(std::string name);
};

MovieList::MovieList() {
numberOfMovies = 0;
}

int MovieList::size() {
return numberOfMovies;
}

void MovieList::add(Movie movie)
{
numberOfMovies++;
movies[movie.getName()] = movie;
}

bool MovieList::containsMovieNamed(std::string name)
{
map
<
std::string, Movie
>
::iterator result = movies.find(name);
return result != movies.end();
}






We also need to extend Movie to retain
its name (and add a default constructor to satisfy the requirements
of map):




class Movie {
private:
std::string name;

public:
Movie();
Movie(std::string aName);
std::string getName();
};

Movie::Movie()
{
name = "";
}

Movie::Movie(std::string aName)
{
name = aName;
}

std::string Movie::getName()
{
return name;
}











As you can see, we are now duplicating the
information about how many movies have been added. We keep track of
it explicitly (as before) and it is also available as an attribute
of the map. To remove it, we first change size to
return the information fetched from the map:




int MovieList::size() {
return movies.size();
}






The tests still pass, so we can remove all of
the code related to explicitly counting how many movies have been
added. Now MovieList is:




class MovieList {
private:
map
<
std::string, Movie
>
movies;

public:
MovieList();
int size();
void add(Movie aMovie);
bool containsMovieNamed(std::string name);
};

MovieList::MovieList() {
}

int MovieList::size() {
return movies.size();
}

void MovieList::add(Movie movie)
{
movies[movie.getName()] = movie;
}

bool MovieList::containsMovieNamed(std::string name)
{
map
<
std::string, Movie
>
::iterator result = movies.find(name);
return result != movies.end();
}


















































Amazon






No comments: