TDD
Goals
This assignment has the following goals:
- Learn how to tackle a programming assignment incrementally.
- Learn the basics of test-driven development
- Prepare to do HW05.
Overview
In this class—and virtually all future programming courses—the only viable way to build up a project is to build it incrementally, while testing and re-testing your implementation at every step. For many students, it can take a long time to learn this valuable lesson.
How to spend less time debugging (and more time enjoying the sunshine)
Let's illustrate t by example. Consider two approaches to doing HW05:
-
Student X reads the description, thinks it through, and then codes up the entire solution. Then, they write all the tests at once. When they run the tests, there are dozens of compiler warnings and errors. After solving those, they find that none of the code works. They debug one issue after another until finally, everything works*.* This is optimistic. Sometimes, they miss the deadline.This chart shows Student X's time:=read =write new code =test/debug =write tests
-
Student Y reads the description, thinks it through, and then starts on a very small amount of functionality (e.g., printing an empty string, or a single character). Before they write any code in their
mintf(…)
, they put a line in their test_mintf.c and the expected output in their test_mintf.txt. Then, they add just enough code to theirmintf(…)
to make it pass that first test. Then, they add another test for little more functionality (e.g., printing an integer by itself withmintf("%d", 768336)
). After adding the test, they add just enough code to theirmintf(…)
so that it passes that test, and the previous tests. It still doesn't do everything it needs to, but it does a few things perfectly, and there is no broken code.Each step in the process is short—about 2 minutes to add a test, and 5-10 minutes to augment theirmintf(…)
implementation code—so their code is never broken for more than about 10 minutes at a time. Once they've added all of the required features, the code works perfectly. There is no major debugging step at the end.This chart shows Student Y's time:=read =write new code =test/debug =write tests
Student X and Student Y spend the same amount of time reading, coding, and making tests. The difference is that if Student Y has a bug, it must have been introduced no more than about 10 minutes ago, since the code is never broken for more than about 10 minutes at a time. When Student X has a bug, it could be practically anywhere, so each bug takes much longer to diagnose and fix.
Although this is just an illustration, it is based on our observations of students in past semesters, our own experiences, and a well-established software engineering process. Our version of TDD is simplified, but the core process is the same.
Test-driven development
To begin, first create an empty test code file (e.g., amain(…)
with just one line:
return EXIT_SUCCESS;
) and an empty output file (e.g., empty text file).
Make sure your testing process is working by simply running the test code file
and verifying that the output matches the test output file. (Commands were given in
HW02.) Then, proceed as follows:
- Create test. Choose the smallest/easiest piece of functionality that you can add to your implementation file (mintf.c). Add a test to your test code file (test_mintf.c) and the expected output in your test output file (test_mintf.txt).
- Add code. Write just enough code so that the new test passes. Your impelementation won't be complete yet, but everything you've written so far should work.
- Test. Check that your code now passes all of the tests written so far. If anything doesn't work, fix it before you go on. At the end of each cycle, 100% of your code should be working, even though some parts for other features may not be written yet.
Instructions
Read the instructions for HW05 before you proceed.
Create a file called plan.c with only a main(…)
function.
In the main(…)
function, write out a series of at least 10
stages that you will use to build your HW05
incrementally using TDD. Each stage must be in the following form:
// Test ## TEST_CODE // Expect: "EXPECTED_OUTPUT"
These stages will trace the steps from beginning your HW05 to finishing it. Each stage adds a small amount of required functionality that was not present in previous stages.
Later, when you implement your code for HW05, your code should never be broken for more than 10-15 minutes at a time, because you will be writing it in very small increments. After each stage, you will get your code completely working—for that subset of the functionality.
Assume that you are starting with a working
print_integer(…)
. Thus, you do not need to
have steps for testing internal aspects of
print_integer(…)
. You are planning the development
of your mintf(…)
function
for HW05.
More detailed criteria are given below under Requirements.
Note: Your plan.c will not be compiled or run by us. Instead, it is just serving as a sort of document for you to communicate your planned stages to us. Yes, this is weird.
Definitions: For purposes of these instructions, “implementation code” means your mintf.c; “test code” means your test_mintf.c; “test output” means your test_mintf.txt; and “test” means a small section of your plan.c (most likely in the main(…)
and the corresponding snippet in your test_mintf.txt, which together can be used to verify that some aspect of your program works according to the specification.
Starter code
Requirements
- One file is required: plan.c
- Your plan.c must contain a
main(…)
containing ≥10 stages meeting the following criteria:- Stage 00 is an empty test to check your testing framework. It should always pass.
- Tests for all stages from 0 to n pass with the implementation for stage n. In other words, the changes you make in stage i will not require breaking any of the tests associated with previous stages.
- Implementation code in stage i would fail the tests for stages <i.
- Implementation code in stage i+1 will be different from code in stage i.
- Implementation code in stage n+1 will add required functionality that was not in stage n.
- Implementation code in stage n+2 has more sloc* than implementation code for stage n.
* sloc = “source lines of code” (excluding comments and blank lines)
-
Altogether, the tests will comprehensively test your final implementation of
mintf(…)
for HW05. In other words, any implementation ofmintf(…)
that passes all of your testsmustshould be working perfectly.
- Each stage must be in the following format:
// Test ## TEST_CODE // Expect: "EXPECTED_OUTPUT"
- Special for this assignment:
- You may copy anything in the screenshot, including stages 00 and 01. The rest of your test cases must be your own.
- Your code does not need to compile or run for this assignment (HW03).
While these requirements may initially sound complex, they are not. If you are following the spirit of the TDD method, all of this will almost certainly happen naturally.
Scoring
Scores will be based on how well your steps follow the requirements.
Submit
To submit HW03 from within your hw03 directory,
type
264submit HW03 plan.c
Q&A
-
Will there be partial credit?
No. -
Will this be accepted late?
No. -
How many mistakes will you accept while still giving credit?
≥0. -
Why is this due before HW05?
It will be more useful if you do it before you get too far into HW04. -
What if I have already finished HW05?
If you followed TDD, you can use this to explain your process. If not, you can use this to explain how you could have used TDD for HW05. -
Is this unfair to those who already finished HW05?
Maybe a little, but everyone can benefit. Also, it's a small thing. As of the time of posting this (Mon 2/3/2020 morning), 31.7% of the class had started, 6.9% had submitted something, and 1.5% had submitted something that passes the current pretester.