Download presentation
Presentation is loading. Please wait.
1
Testing (Continued)
2
Test-Driven Development
The tests are the detailed specification And now can be executed, not just read More tests Fewer specification documents
3
Types of Tests System: End-to-end tests
User-like input to end-user output End to End Tests Unit Tests Test small pieces of system (single classes / functions) Unit Tests
4
System Tests vs. Unit Tests
Strengths/Weaknesses of System Tests Strengths/Weaknesses of Unit Tests
5
System Tests vs. Unit Tests
Strengths/Weaknesses of System Tests Test entire system no gaps Hard to debug: problem could be anywhere! Fragile: often test exact user input would produce exact output text / file Strengths/Weaknesses of Unit Tests Easier to debug: start with 1 class / function Less fragile: Don’t check user interface (I/O): check API / class does what it should with code (testfixture) Don’t test whole system gaps possible
6
Types of Tests Fewer Integration Tests Bigger unit tests
(but not 0!) End to End Tests Integration Tests Bigger unit tests But now test multiple classes / bigger functionality Moderate difficulty to debug Integration Tests Unit Tests More
7
Unit Tests Want: No! To test individual classes / functions How?
Carefully chosen user input? Output ... No! struct Point { float x; float y; t_point& operator*=(float rhs); . . .
8
Unit Tests Write new code To put class in right state
To directly send it some input / make some calls To immediately check the responses Test driver
9
Unit Tests myCode.cpp struct Point { float x; float y;
t_point& operator*=(float rhs); . . . tester.cpp int test1 () { Point testme (1, 2); testme *= 3; if (testme != Point (3, 6)) { cout << “uh – oh” << endl; return (1); } return (0); test_main.cpp g++ myCode.cpp main.cpp –o prog.exe int main () { int error = 0; error += test1(); . . . // Lots more tests g++ myCode.cpp tester.cpp test_main.cpp –o test.exe
10
Unit Test Frameworks Lots of repetitive code to create test drivers
Set up the test Check if the test passed Run all the tests Output appropriate messages Collect statistics Unit Test Frameworks Useful macros (#defines) and functions to simplify coding We are using UnitTest++ Powerful, but easy to learn ECE 297 Unit Test Quick Start Guide TEST(..) or TESTFIXTURE (…) CHECK(..) RunAllTests() Automatic Automatic
11
“Test the Seams” Overlapping tests good Therac-25
Your code + partner’s code Both unit tested Make sure there’s an integration test Therac-25
12
Testing Tools What tools? Debugger Memory checker
Use to debug when a test fails Use to verify new code Step through it and watch execution Memory checker Program seg faults? Program behaving very strangely? Maybe you are accessing memory you shouldn’t be! Run debug_check configuration and/or valgrind
13
Testing Tools 3. Code coverage
Tools that can track what lines of your programs have executed over all your tests MyCode.cpp int someFunc (int input) { if (input == 0) return (3); else return (7); } main.cpp int main () { int j = someFunc (8); // Wow I’m bad at testing! }
14
Testing Tools 3. Code coverage
Tools that can track what lines of your programs have executed over all your tests MyCode.cpp int someFunc (int input) { if (input == 0) return (3); else return (7); } No test reaches this line. Code coverage: 6 out of 7 lines or 86% main.cpp int main () { int j = someFunc (8); // Wow I’m bad at testing! }
15
Google: Testing so Important, Tutorials in the Bathroom
16
“Testing on the Toilet”
17
Automate Build & Tests Make it easy to do the right thing Ece297:
One command to build One command to test One command to submit Google Also easy to build, test Easy to deploy Send to the real web site and real users Split into A/B test (e.g. 2% of web traffic gets new ad engine) Easy to reverse deployment if a bad idea Continuous deployment: requires good automated tests
18
Good Coding Style
19
1. Use White Space White space: show code organization
int sumVec (int vec[], int nElem) { int i, result = 0; for (i = 0; i < nElem; i++) { result += vec[i]; } return (result); void nextFunc (int i) { … int sumVec (int vec[], int nElem) { int i, result = 0; for (i = 0; i < nElem; i++) { result += vec[i]; } return (result); void nextFunc (int i) { White space: show code organization Indent properly (3 or 4 spaces) per { }. Leave blank lines between functions / key blocks
20
float di (float a, float b) { float val, d, x, x2, y; d = 1
float di (float a, float b) { float val, d, x, x2, y; d = 1.e-4; val = 0; for (x = a; x < b; x += d) { x2 = x + d; if (x2 > b) x2 = b; y = 0.5 * ((1. / x) + (1. / x2)); val += y * (x2 - x); } return (val); What does this do?
21
float definite_integral (float x_left, float x_right) { float integral, step_size, x1, x2, y_average; step_size = 1.e-4; integral = 0; for (x1 = x_left; x1 < x_right; x1 += step_size) { x2 = x1 + step_size; if (x2 > x_right) x2 = x_right; y_average = 0.5 * ((1. / x1) + (1. / x2)); integral += y_average * (x2 – x1); } return (integral); What does this do?
22
2. Descriptive Variable Names
Use descriptive names Variables, functions, structs/types, … get_file_name ( ); // Use _ to separate getFileName (); // Or use upper case to mark words Types: start with a capital letter Variables: start with lowercase class MyClass { … MyClass oneVar;
23
float definite_integral (float x_left, float x_right) { float integral, step_size, x1, x2, y_average; step_size = 1.e-4; integral = 0; for (x1 = x_left; x1 < x_right; x1 += step_size) { x2 = x1 + step_size; if (x2 > x_right) x2 = x_right; y_average = 0.5 * ((1. / x1) + (1. / x2)); integral += y_average * (x2 – x1); } return (integral); What does this do?
24
Comment what whole function does
// Compute the definite integral of 1/x between x_left and x_right via the // trapezoidal method. Smaller values of step_size improve accuracy, but // increase computation time. float definite_integral_of_one_over_x (float x_left, float x_right) { float integral, step_size, x1, x2, y_average; step_size = 1e-4; integral = 0.; for (x1 = x_left; x1 < x_right; x1 += step_size) { x2 = x1 + step_size; if (x2 > x_right) // in case (x_right – x_left) is not a multiple of step_size x2 = x_right; y_average = 0.5 * ((1. / x1) + (1. / x2)); // average of y(x1) and y(x2) integral += y_average * (x2 – x1); } return (integral); Comment what whole function does Comment any tricky bits of code
25
Comments: Usefulness? asteroids.cpp
/* This file implements an asteroid AI. It maintains * a current position and velocity for each asteroid and * the ship. It divides the screen into N bins, and * computes the desirability of moving the ship * to each bin by computing the time at which the ship * could it, and the bin’s asteroid density at that time. */ StudentRecord.h /* Main data structure used to store all information * about a U of T student. Linked list. */ struct StudentRecord { int nClassesCurrent; // Number enrolled, current semester int nClassesComplete; // Number completed & passed StudentRecord *next; // Pointer to next (linked list) record program.cpp // Compute the sum of the array, over all its elements int sum = 0; for (int i = 0; i < nElem; i++) sum += array[i];
26
3. “High-Level” Comments
Most important comments: give the big picture Documentation should be in the comments Not a separate document will get out of date Top of files // Functions to simulate resistor network. Proceeds in 6 stages … Class / data structure definitions Understand the data can understand the program! Start of functions Tricky code Not useful: Comments that translate C++ to English Most important Least important
27
Thoughts on This Code? Using a “magic number”: 20
int checkWeights (int weights[20]) { for (int i = 0; i < 20; i++) { if (weights[i] < 0) return (-1); if (weights[i] == 0) return (0); } return (1); Using a “magic number”: 20 Change array size: must find and change all 20’s Returning magic numbers: -1, 0, 1 Must read code carefully to see what each means
28
4. Use Named Constants const int NUM_WEIGHTS = 20; // 1. Constant variable #define WEIGHT_ZERO // 2. Pre-processor constant enum WtReturn {HAS_NEG = -1, HAS_ZERO = 0, ALL_POS = 1}; // 3. make an “enumeration” (list) of int constants int checkWeights (int weights[NUM_WEIGHTS]) { for (int i = 0; i < NUM_WEIGHTS; i++) { if (weights[i] < 0) return (HAS_NEG); if (weights[i] == 0) return (HAS_ZERO); } return (ALL_POS); Three ways to make constants use any way you like Name: ALL CAPITALS (convention)
29
5. Many Short Functions Short functions Easier to re-use
Fix bugs in one place, not many Make code easier to read: more abstraction How long should functions be? Should have many 5 to 10 line functions Should very rarely have a function > 100 lines
30
There is no honour in copy
Thoughts on This Code? #include <math.h> void myFunc (float a[], float b[], int nvals) { float absAvg1 = 0; for (int i = 0; i < nvals; i++) absAvg1 += abs(a[i]); absAvg1 /= nvals; float absAvg2 = 0; absAvg2 += abs(b[i]); absAvg2 /= nvals; ... } There is no honour in copy and paste coding! Refactor!
31
Better Version? 1. Not much shorter, but easier to read
#include <math.h> float compAbsAvg (float array[], int nvals) { float absAvg = 0; for (int i = 0; i < nvals; i++) absAvg += abs (array[i]); return (absAvg / nvals); } void myFunc (float a[], float b[], int nvals) { float absAvg1 = compAbsAvg (a, nvals); float absAvg2 = compAbsAvg (b, nvals); ... 1. Not much shorter, but easier to read 2. Less chance of more code copying future code will be shorter
32
6. Don’t Do Too Much in a Statement / Line
#include <string> #include “StreetsDatabaseAPI.h” string name = getIntersectionName(getStreetSegmentInfo( getIntersectionStreetSegment(0,startInter)).to); // Hard to read! unsigned firstSeg = getIntersectionStreetSegment (0,startInter); unsigned destInterId = getStreetSegmentInfo(firstSeg).to; string destInterName = getIntersectionName (destInterId); // Show your work divide into several steps on several lines // Use good variable names to show what intermediate results // are.
33
7. Group Related Data into Classes
vector<int> fromIntersectionofSegment; vector<int> toIntersectionofSegment; vector<float> speedLimitofSegment; vector<double> lengthofSegment; class SegmentData { public: int fromIntersectionIdx; int toIntersectionIdx; bool oneWay; // If true, can only go from -> to float speedLimit; // In km/h double travelTime (); // Returns travelTime in s } vector<SegmentData> segmentInfo; // [0..numStreetSeg-1] 1. Groups related data and functions 2. Less name pollution
34
8. Defensive Coding Use assertions to verify assumptions in your code
void myFunc (int *ptr) { // Don’t ever call myFunc with a NULL ptr! if (*ptr == 1) { … #include <assert.h> assert (ptr != NULL); Exits program if ptr is NULL (condition not true) Better than a comment: Checked at runtime & gives useful error message > assert failed on line 208 of file myFunc.cpp: ptr != NULL
35
What If I Need That Last Bit of Speed?
#define NDEBUG // Just turned off assertion checking // Make sure this line is in front of // #include <assert.h> #include <assert.h> void myFunc (int *ptr) { ptr = NULL; assert (ptr != NULL); // Not checked won’t fire. … Can turn off assertion checking in release build Avoids any speed overhead Leave on for debug build for extra checking And maybe leave on in release too if your program not very time critical
36
8. Defensive Coding B. Set deleted / invalid pointers to NULL
delete (ptr); ptr = NULL; // Now we’ll crash if we try to use it good! … ptr->value = 1; // Will seg fault immediately C. Self-checking code (advanced technique) program_ok = validate_key_data_structure (my_struct);
37
Should have used assert or validity checkers!
38
Find the Bug! const int NUM_WEIGHTS = 20; // 1. Constant variable #define WEIGHT_ZERO 0 // 2. Pre-processor constant enum WtReturn {HAS_NEG = -1, HAS_ZERO = 0, ALL_POS = 1}; // 3. make an “enumeration” (list) of int constants int checkWeights (int weights[NUM_WEIGHTS]) { for (int i = 0; i < NUM_WEIGHTS; i++) { if (weights[i] = 0) return (HAS_ZERO); if (weights[i] < 0) return (HAS_NEG); } return (ALL_POS); Test program, find a failing case … weights = {-1, 2, 3, 4, 5, 6, … 20} checkWeights returns ALL_POS
39
9. Use Compiler Warnings > g++ -Wall weights.cpp > weights.cpp: In function ‘int checkWeights(int*)’: > weights.cpp:11: warning: suggest parentheses around assignment used as truth value int checkWeights (int weights[NUM_WEIGHTS]) { for (int i = 0; i < NUM_WEIGHTS; i++) { if (weights[i] = 0) return (HAS_ZERO); if (weights[i] < 0) return (HAS_NEG); } return (ALL_POS); Line 11
40
Warnings in your code lower style mark
9. No Warnings Don’t have any warnings in your code Warnings flag potentially problematic code If you leave some warnings in, hard to see new ones Fix right away: stay at 0 warnings! Tell compiler to generate all useful warnings (more than default) Command line: g++ –Wall <…> We turn on all warnings we consider useful in your makefile Warnings in your code lower style mark
41
Summary: One Code Base to Rule Them All
Code will be read more than written By you By others Make it readable! Code will be modified many times Make small functions & avoid repeated code Keep the tests with the code Automated, so you can re-run often Keep documentation in the code -- comments!
42
Read code as a team & share feedback
Code Reviews If you do one thing for code quality code reviews Altera/Intel: periodic review 4 reviewers read code written by one team member Significant amount: ~400 – 1000 lines Write down thoughts Then meet to discuss readable, clear, efficient? Google: every commit reviewed and approved Integrated into source code control system Change not visible to others until reviewed & approved Read code as a team & share feedback
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.