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(); }
|
No comments:
Post a Comment