23
Testing and Debugging Hakam Alomari [email protected]

Testing and Debugging

  • Upload
    mirit

  • View
    56

  • Download
    1

Embed Size (px)

DESCRIPTION

Testing and Debugging. Hakam Alomari [email protected]. Outline. Include Guards Namespace name access Testing Concepts What is software testing? How to find faults? Black Box vs. Glass Box testing How many tests cases are there? Regression testing Using assert and cerr - PowerPoint PPT Presentation

Citation preview

Page 1: Testing and Debugging

Testing and Debugging

Hakam [email protected]

Page 2: Testing and Debugging

Outline

• Include Guards• Namespace name access• Testing Concepts– What is software testing?– How to find faults?– Black Box vs. Glass Box testing– How many tests cases are there?– Regression testing

• Using assert and cerr• Building test cases, Makefile

Page 3: Testing and Debugging

Include Guards

• Are used to prevent the contents of a file from being included more than once– Example: (string.h)

#ifndef CS2_STRING_H#define CS2_STRING_HClass string {

//…

};#endif

Page 4: Testing and Debugging

Example [wiki]

File "grandfather.h“struct foo {

int member;

}; File "father.h“

#include "grandfather.h" File "child.c“

#include "grandfather.h" #include "father.h"

Page 5: Testing and Debugging

Use of #include guardsFile "grandfather.h“

#ifndef GRANDFATHER_H #define GRANDFATHER_H struct foo {

int member;

}; #endif

File "father.h“#include "grandfather.h"

File "child.c“#include "grandfather.h" #include "father.h"

Page 6: Testing and Debugging

Namespaces• Used to group entities (e.g., objects) under a name, such as each group

has its own name• Example:

namespace foo1 {int var = 1;

}namespace foo2 {

int var = 2;

}

int main () {std::cout<< foo1::var <<“\n”; // output 1std::cout<< foo2::var <<“\n”; // output 2return 0;

}

Page 7: Testing and Debugging

Standard Includes

• Names defined by standard includes (e.g., cout) can be used as: – Prefix the name with std::– Use using std::name before the name is used– Put using namespace::std before the name is used– Example:

int main() { std::cout << "Hello World!\n"; // ...

int main() { using std::cout; cout << "Hello World!\n"; // ...

using namespace std; int main() { cout << "Hello World!\n"; // ...

Page 8: Testing and Debugging

Software Testing

• Software testing is used to find errors • error:– Incorrect output for a given input– Caused by faults inside the program– A fault is represent the incorrect part of the code• E.g., incorrect stopping condition

• So, test cases should be developed to exercise the program and uncovering errors

Page 9: Testing and Debugging

Testing levels

• Start by testing each method (unit tests)• Then each class in full (module tests)• Then the whole program (system tests)

• The test case that has a high probability to uncover an error is known to be the best one

Page 10: Testing and Debugging

Testing Types

• Black box vs Glass box (white box)– Black box• Uses only the I/O spec. to develop test cases

– Glass box • Uses only the implementation details to develop test

cases

• Both types are necessary to develop a good set of test cases

Page 11: Testing and Debugging

Number of Test Cases

• Functions usually have a very large number of pre. and post. conditions

• So, there is no need to test all of these to make sure our function behaves correctly

• How?– Pairing down test cases, by:– Develop equivalence classes of test cases– Examine the boundaries of these classes carefully

Page 12: Testing and Debugging

Equivalence Classes

• The input and output often fall into equivalence partitions where the system behaves in an equivalent way for each class

• Then, the test cases should be developed to test each partition

Page 13: Testing and Debugging

Classes Boundaries

• Example:– Partition system inputs and outputs into

equivalence classes– If input is a 2 digit integer between 10 and 99

then the equivalence partitions are < 10 (invalid), 10 – 99 (valid), and > 99 (invalid)

– Choose test cases at the boundary of these partitions

– 09, 10, 99, 100

Page 14: Testing and Debugging

Building Test Cases

1. Determine the I/O spec. for the method2. Develop test cases3. Method implementation 4. Run the method against the test cases

from 25. Debugging (fix)6. Go to 4

Page 15: Testing and Debugging

Test Steps• There are three steps in a test:

– Set-up the "fixture", the system to be tested– Perform the test– Verify the results, make sure there are no unwanted side effects

• Example: Test for existence of const char& operator[](int) const – // Setup fixture

• const string str("abc"); – // Test

• assert(str[0] == 'a'); • assert(str[1] == 'b'); • assert(str[2] == 'c');

– // Verify • assert(str.length() == 3);

Page 16: Testing and Debugging

Regression Testing

• The intent of regression testing is to ensure that a change, such as a bugfix, did not introduce new faults

• Each time you add a new method to your class or fix a fault run your test cases (all of them)– Adding something new or fixing a problem may

have side effects• Re-running your test cases will uncover these

problems

Page 17: Testing and Debugging

Asserts

• Used to output an error message and terminate a program if a condition is false

• Asserts are useful for testing• #include <cassert> is required to use asserts• Example:– assert(result == correct_result);

• Asserts can be turned off using– #define NDEBUG

Page 18: Testing and Debugging

Debugging• Used when the program is not working properly • One easy thing to do is output the value of relevant variables• Use cerr instead of cout. cout is buffered• Buffering means output is accumulated in a "buffer" and the

accumulated output sent out to the OS together• Output to cerr is not buffered, it is output immediately• If a program crashes there may be output in a buffer that gets

lost• It is a good idea to include a message with values that are

output– std::cerr << "var1 = " < < var1 << "\n";

Page 19: Testing and Debugging

The make Command

• The make command may be used to automate compiling

• The make command when executed will look for a file named makefile and then, if not found, for a file named Makefile to specify dependencies

• Otherwise a makefile must be specified with the -f option

• The make command has some rules built-in so it can do some basic compiling but usually the developer provides a makefile

Page 20: Testing and Debugging

Makefile Rules• Rules have the form:

– target: dependency_list – TAB command

• Target A file or name• dependency_list Files that the target "depends on"• TAB The TAB character. REQUIRED!• Command Typically a compiling/linking command

but can be any command. There may be more than one TAB/command line

• If the modification time of any dependency is more recent than the target the command lines are executed

Page 21: Testing and Debugging

Common Rule Types

• Creating machine language, .o, files and linking are two things that must be done# Link executable: file_1.o file_2.o

g++ -Wall file_1.o file_2.o -o executable

# Create .o file file.o: file.h file.cpp

g++ -Wall -c file.cpp

• Note .cpp files are typically not targets, .cpp files do not depend on other files

Page 22: Testing and Debugging

Makefile Example# Create the executable is the first rule here # Link main: bigint.o main.o

g++ -Wall bigint.o main.o -o main # Create .o file main.o: bigint.h main.cpp

g++ -Wall -c main.cpp # Create .o file bigint.o: bigint.h bigint.cpp

g++ -Wall -c bigint.cpp # Remove .o and executable clean:

rm -f *.o rm -f main

Page 23: Testing and Debugging

References

• [wiki]: http://en.wikipedia.org/wiki/Include_guard

• Computer Science II Lab: http://classes.cs.kent.edu/courses/cs33001_lab/svn/index.html

• Software Testing for CS II slides: http://www.cs.kent.edu/~jmaletic/CS33001/