CSC161 2010F, Class 24: Unit Testing Overview: * Unit Testing. * Unit Testing Frameworks. * Questions. * Example: Average. * Example: Binary Search. Admin: * EC for tomorrow's cool CS extra: Shitanshu on his work at Amazon (or at least the parts he's allowed to tell you about). * EC for FreeNet meeting Sunday at 10 p.m. in Main Lounge * No EC for people related to Asa * No reading for Friday! * Reminder: SUBMIT QUESTIONS! * Checking: Do you know where to find the sample code we build each day? * Today is a lecture / recitation class. I talk. I ask questions. You answer questions. We build programs along the way. Unit Testing * Perspective on program design: It's good to test your code. * After all, we're scientists * Even the best of us sometimes make mistakes, even when we think we have everything rihgt * Strategy one: Write a few sample calls to the procedure and look at the output * Strategies two a, b, and c: Write an interactive or command-line tester * Unit testing goes beyond this a bit * More like strategy one: Hard-coded tests * And thoughtful * Theory: Any useful test should be written down anyway. * Unit testing follows the Unix philosophy: If every test succeeds, there's no output! If tests fail. only those tests are printed. * Also: * Write the tests *before* you write the code * Why? * A clearer description of *what* the procedure is supposed to do * Inputs * Outputs * Etc. * Lets you focus on the core functionality rather than unnecessary things. * "Hmmm ... none of the tests assume the denominator is 0, so I don't have to deal with that case." * Evidence suggests that programmers say "I'll write the tests later." and "later" never comes. * If you write the tests later, you've made a lot of assumptions about what the code should do, and are therefore less likely to check the cases in which your code will fail. * Run the tests regularly, after each change to your code (or at least before sharing it with anyone else) Unit Testing Frameworks * Example: JUnit, XUnit * Goal: Ease unit testing * You mix tests and code * Run program normally, tests get ignored * UTF can identify the tests and run them all appropriately * A good UTF can just be told "Test everything" So ... * Unit testing requires * Ability to think of good tests * Habits of building those tests and regularly running them Questions * Unit testing seems to focus on a bottom-up development methodology. Is that really the case? * Works for any methodology that ends up with programmers implementing small units. Top-down, bottom-up, sideways-backwards, whatever * How do programmers break up the testing? * Those responsible for a unit write the tests (sometimes testers write tests) * Everyone reads the tests to make sure that they agree on what each unit is suppoed to do * Is this like building a lot of helper procedures and testing them all individu ally instead of just testing the main function at the end? * Yes * Do we test all possible/probable inputs? * No. Too many. * Document or write tests first? * Simultaneous * How do you decide which tests suffice? * Careful thought * Experience * What is "continuous integration"? * Smalla milestones instead of big * What do unit tests look like? * Let's see! Example one: Average * How might we write a command-line tester E.g., average 1 2 3 4 5 computes the average of 1 2 3 4 5 * Turn the array of strings (argv) into an array of integers * (Maybe) print out the array for clarity * Compute the average * Print out the average * How do we turn an array of strings into an array of integers * For loop to step through the positions * atoi to convert a single string into an integer * How do I build an array that can store the integers? int values[MAX_SIZE]; or int values[argc-1]; * Which one? * argc-1 * Only as large as it needs to be * No limit to the size (well, at least not MAX_SIZE limit) * MAX_SIZE * Given what you know so far, you can't declare an array whose size depends on a variable that is computed at run-time. A Problem with Average Identified by Good Testing * If the sum of the values is greater than INT_MAX, it breaks. * But if the result should be less than INT_MAX and greater than INT_MIN, it shouldn't break. * How can we stop it from breaking? * Use longs * Good idea, but won't work if we try to average longs and use LONG_MAX * Use floats or doubles * Approximation is not you friend * Make sure the sum never exceeds INT_MAX * But you can't * Divide first and then add * Problem: What about the leftover stuff average({1,1,1,1}) should be 1 But 1/4 is 0 * Solution: Keep track of the leftover stuff, too!