$29
Topics: Design, testing, UML, unit tests
Turn in: Turn in all source les - .cpp, .hpp, and/or .h les. Do not turn in Visual Studio les.
Starter les: Download from GitHub.
Building and running: If you are using Visual Studio, make sure to run with debugging. (Don't run without debugging!) Using the debugger will help you nd errors.
To prevent a program exit, use this before return 0;
cin.ignore();
cin.get();
Tips:
Always make sure it builds. Only add a few lines of code at a time and build after each small change to ensure your program still builds.
One feature at a time. Only implement one feature (or one function) at a time. Make sure it builds, runs, and works as intended before moving on to the next feature.
Search for build errors. Chances are someone else has had the same build error before. Copy the message into a search engine and look for information on why it occurs, and how to resolve it.
Use debug tools, such as breakpoints, stack trace, and variable watch.
Don't implement everything in one go. Don't just try typing out all the code in one go without building, running, and testing. It will be much harder to debug if you've tried to program everything all at once.
About
Linear data structures may be implemented in di erent ways behind-the-scenes, but the general functionality should still result in the same outcome. For this project, you will design and implement unit tests for a linear struc-ture, and these tests will be tested against the Bag data type, a smart Dy-namic Array, and eventually the Linked List object.
Test les
In the starter code, there are the following les:
tester program.cpp - contains main()
Tester.hpp - the class and function declarations Tester.cpp - the tester function de nitions
List.hpp - A List class, with stub functions
The List class will have placeholders in the methods so that the program will be buildable. You will remove the placeholders as the functions are being implemented.
Before implementing the functions, your rst task is to implement the tests. As you implement the tests, they will start of failing (for the most part), which is good. Then, when you implement the actual functionality, you can validate that it works as intended by whether it passes the tests.
Your tests may not be correct at rst since this might be a new concept, so in some cases it is okay to adjust your tests. You might also have to add additional test cases to more fully cover the functionality.
Once these tests are implemented and working with a static array-based list, then the tests should also theoretically work with other linear structures.
Three turn ins
You will turn in this project in three parts: First, the Test Outline document (edit in LibreO ce or MS Word and turn in). Second, the test implementa-tions in the code. Third, the full List implementation.
Part 1 - Planning Tests
Make sure you download the Test Outline document. This is a document you can open up in MS Word or LibreO ce. Work on planning your test sets during class. You can also brainstorm with other students on this part.
Your tests should, at minimum, cover all reasonable outputs. For example, for something that returns a boolean, we should have tests that expect a true and a false as outputs. For a function that returns an integer, such as Size(), you won't test all possible outputs, but at least for 0, 1, and several other values.
Figure 1.1: An example of tests for the IsEmpty() function, in the Test Outline document.
We will work on this part during class, and for Part 1 of the project you can brainstorm and collaborate with other students. However, keep in mind that your code in Part 2 and Part 3 should be your own.
Part 2 - Writing Tests
For this part of the project you should be working just on the tests, not the List functions. You will upload this project in two parts: Just the tests, and then the tests with the List code.
Reference the Function Speci cations section for descriptions of the functions
Writing unit tests
Each unit test is meant to test one function each, though you might have to rely on multiple functions to fully validate a function. For example, to test the Size() function, you need to be able to add new items to the list, so Push(...) will have to be implemented for the Size() test to work properly.
Each test function may need multiple tests to properly coverage all reasonable use cases.
For each test, you will need to decide on inputs to pass in, and the expected output. To get the actual output, you will call the function being tested, and store its return value in a variable.
You can use an if statement to check whether the actual output matches the expected output. If they match, the individual test can pass. If they don't match, the test fails.
It's up to you for what to output to the screen, though generally it helps if you output the inputs and outputs, and whether the test passes or fails.
Tests to implement
The tests to implement are:
Test
Init()
Test
ShiftRight()
Test
ShiftLeft()
Test
Size()
Test
IsEmpty()
Test
IsFull()
Test
PushFront()
Test
PushBack()
Test
PopFront()
Test
PopBack()
Test
Clear()
Test
Get()
Test
GetFront()
Test
GetBack()
Test
GetCountOf()
Test
Contains()
Test
Remove()
Test
Insert()
By Rachel Singh, last updated January 5 of 16
CS 250, Project 1: Unit Tests and Linear Structures
Example test:
void Tester :: T es t_ Si ze ()
{
DrawLine () ;
cout << " TEST : Te st _S iz e " << endl ;
{ // Test begin
cout << " \ n \ n Test 1 " ;
List < int testList ;
int e x p e c t e d S i z e = 0;
int a c t u a l S i z e = testList . Size () ;
cout << " \ n Expected size : " << e x p e c t e d S i z e ;
cout << " \ n Actual size : " << a c t u a l S i z e ;
if ( a c t u a l S i z e == e x p e c t e d S i z e )
cout << " \ n Pass " ;
else
cout << " \ n Fail " ;
} // Test end
{// Test begin
cout << endl << " Test 2 " << endl ; List < int testList ;
testList . PushBack ( 1 ) ;
testList . PushBack ( 3 ) ;
int e x p e c t e d S i z e = 2;
int a c t u a l S i z e = testList . Size () ;
cout << " \ n Expected size : " << e x p e c t e d S i z e ;
cout << " \ n Actual size : " << a c t u a l S i z e ;
if ( a c t u a l S i z e == e x p e c t e d S i z e )
cout << " \ n Pass " ;
else
cout << " \ n Fail " ;
} // Test end
}
CS 250, Project 1: Unit Tests and Linear Structures
Example output:
An example of a couple of tests failing, since the List functions haven't been implemented yet.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - TEST : T es t _S iz e
Test 1
Expected size : 0
Actual size : -1585510992
Fail
Test 2
Expected size : 1
Actual size : -1585510992
Fail
Part 3 - Implementing the List
Once you've implemented the tests, you will be implementing the List func-tions based on the functionality speci ed. As you get each function working, your tests should be passing.
Note that certain tests may rely on the implementation of other functions, such as Size() needing a Push function implemented in order to test for more cases than just an empty list.
Function Specifications
Figure 1.2: A List class UML diagram, implemented with a static array
IsEmpty
Function header: bool IsEmpty() const
Inputs: None
Outputs: true if there is nothing in the list (i.e., the size is 0), or false if not.
IsFull
Function header: bool IsFull() const
Inputs: None
Outputs: true if the list is full (i.e., the m itemCount is equal to ARRAY SIZE), or false if not.
Size
Function header: int Size() const
Inputs: None
Outputs: Returns the amount of items stored in the list. Will be 0.
GetCountOf
Function header: int GetCountOf( const T& item ) const
Inputs: const T& item, where the list contains items of type T (it is a template). The item to be searched for and counted is item.
Outputs: Returns the amount of instances of item being found in the list. Will be 0.
Contains
Function header: bool Contains( const T& item ) const
Inputs: const T& item, where item is the item to search for.
Outputs: Returns true if item is found in the list, and false other-wise.
List constructor
Function header: List()
Initializes the List class. The list should start o empty.
Inputs: None
List destructor (no tests)
Nothing required for the static array version of the List.
PushFront
Function header: bool PushFront( const T& newItem )
Inputs: const T& item, the new item to add to the list at the begin-ning.
Outputs: Returns true if the operation is a success, and false other-wise.
PushBack
Function header: bool PushBack( const T& newItem )
Inputs: const T& item, the new item to add to the list at the end.
Outputs: Returns true if the operation is a success, and false other-wise.
Insert
Function header: bool Insert( int atIndex, const T& item )
Inserts a new item at the given index. Existing items shouldn't be re-placed. If there is an item already at the index given, it will be pushed towards the end of the list.
Inputs:
int atIndex - the index where to insert the new item. const T& item - the new item to insert.
Outputs: Returns true if the operation is a success, and false other-wise.
Get
Function header: T* Get( int atIndex )
Inputs: int atIndex, the index of the item to return.
Outputs: Returns the address of the item at the index given, or nullptr if it isn't found.
GetFront
Function header: T* GetFront()
Inputs: None
Outputs: Returns the address of the item at the front of the list, or nullptr if the list is empty.
GetBack
Function header: T* GetBack()
Inputs: None
Outputs: Returns the address of the item at the end of the list, or nullptr if the list is empty.
PopFront
Function header: bool PopFront()
Inputs: None
Outputs: Returns true if removing the item is successful, and false otherwise.
PopBack
Function header: bool PopBack()
Inputs: None
Outputs: Returns true if removing the item is successful, and false otherwise.
Remove
Function header: bool Remove( const T& item ) Function header:
bool Remove( int atIndex )
Inputs:
const T& item - locates all instances of this item in the list and removes it.
int atIndex - removes the item at this index.
Outputs: Returns true if removing the item is successful, and false otherwise.
Clear
Function header: void Clear()
Clears out the list. To test this function, you should ensure that the size of the list returns to 0 after this function is called.
Inputs: None
Outputs: None
ShiftRight
Function header: bool ShiftRight( int atIndex )
Moves everything to the right of the index further to the right by one position.
Inputs: int atIndex - The index at which to begin moving items for-ward.
Outputs: Returns true if the shift is successful, or false if not.
ShiftLeft
Function header: bool ShiftLeft( int atIndex )
Moves everything to the right of the index further to the left by one position. This will overwrite the item at the atIndex.
Inputs: None
Outputs: Returns true if the shift is successful, or false if not.
By Rachel Singh, last updated January 14 of 16