CS 70

Test the Car Class

Now we'll start testing some of the code you've written! There are two key aspects to our approach to testing: running tests using the CS 70 testing library, and using Valgrind to detect memory errors.

The testtrain Program

In this part of the assignment, you are going to test out your Car class using the testtrain program. (For this assignment, we gave you very little code to start with, but we did provide testtrain.cpp!)

Take a look at the testtrain.cpp file. There are several test functions that increase in complexity.

The runTests() function runs all the tests. In the provided version of the code, all the tests are commented out. In this step, you will uncomment each of the Car tests one by one to make sure your code does what it is supposed to do.

main() takes in a command-line argument which can be:

  • T — Run a predefined set of tests on the Car and Train classes.
  • B — Run an interactive session using a BASIC train.
  • S — Run an interactive session using a SMART train.

We'll be using the T option at the moment.

  • LHS Cow speaking

    All the testing functions use the CS 70 testing library. In later assignments, you'll have to write your own tests using this library, but in this assignment you just have to use the tests and understand what they do.

Running Programs Using Valgrind

You will also learn about a tool called Valgrind, which runs your program in a special way that allows it to detect three kinds of common errors:

  • Reading from memory that you haven't properly initialized.
  • Reading or writing memory that is way out of bounds.
  • Failing to use the heap properly (especially memory leaks).

Valgrind is not a panacea. It does not detect all errors or all kinds of undefined behavior, but it is still a very useful way to debug your program.

Your Tasks

Reason About Expected Output in Test Cases

Open testtrain.cpp and look at the test cases that involve the Car class (the section of code labeled Car Testing Functions in comments).

Many of the tests output a Car and check that it looks as expected. The tests do not explain why the output is correct, however. You'll have to reason that out for yourself.

Test the Car Class's Constructor and Destructor

The function testDeclareCar() declares a Car and checks some of its informational functions. It causes the Car class's constructor and destructor to be called.

  1. Uncomment the line testDeclareCar(); in runTests().

  2. Compile using make (or cs70-make if you prefer)

  3. See if the testtrain program detects any problems by running it in the normal way:

    ./testtrain T
    
  4. Also run your code using Valgrind to see if it can detect any additional errors, by running

    valgrind --leak-check=full ./testtrain T
    
  5. If you found any errors, fix them and go back to Step 2.

Test Car's printToStream Functionality

Now is a good time to make sure you can print out a Car object before we start doing anything more interesting with it.

  1. Uncomment testOutputEmptyCar(); in runTests().

  2. Recompile, rerun normally and with Valgrind as above, and fix any errors.

When run without valgrind, the output of the test program is easy to see. Here's a sample successful output:

01 test declare car passed!
02 test output empty car passed!

all tests passed! Summary of affirmations:
----
Fails   / Total Issue
0       / 3     [01 test declare car]
0       / 1     [02 test output empty car]

But when you run with valgrind, the output of your program mixed in with Valgrind's output, and you may have to scroll to find the test results.

==79== Memcheck, a memory error detector
==79== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==79== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==79== Command: ./testtrain T
==79==
01 test declare car passed!
02 test output empty car passed!

all tests passed! Summary of affirmations:
----
Fails   / Total Issue
0   / 3 [01 test declare car]
0   / 1 [02 test output empty car]

==79==
==79== HEAP SUMMARY:
==79==     in use at exit: 0 bytes in 0 blocks
==79==   total heap usage: 35 allocs, 35 frees, 74,104 bytes allocated
==79==
==79== All heap blocks were freed -- no leaks are possible
==79==
==79== For lists of detected and suppressed errors, rerun with: -s
==79== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

In both cases, you can see that all tests passed.

Make Sure You Can Run the Remaining Car Tests

There are several more test functions for Cars. They do various things, such as add packages to cars; add and remove packages; add and print then remove and print; and so on. Make sure your code does the right thing for each of the tests by uncommenting them one at a time, compiling, and running them.

Optional: You can write more tests!

There is no guarantee that our set of tests will find all possible correctness or memory errors in your code. We always suggest that you come up with tests of your own if you think it will help you'll debug your program. We won’t specifically evaluate your test code (this time!), but we will check the correctness of your code with our own extensive suite of tests—and correctness certainly factors into your grade!

  • Duck speaking

    I'll add tests to check undefined behavior!

  • LHS Cow speaking

    NO! Never break the rules to try to test undefined behavior. Your testing code always has to follow the rules. If you're not allowed to do something, your testing code can't do that thing.

  • Cat speaking

    Do we get extra credit for writing extra tests?

  • LHS Cow speaking

    Sorry, no. But getting some practice will help you in future assignments.

  • Goat speaking

    Guess what I'm not doing. Meh.

To Complete This Part of the Assignment…

You'll know you're done with this part of the assignment when you've done all of the following:

(When logged in, completion status appears here.)