CPSC 315 – Programming Studio Spring 2017

Slides:



Advertisements
Similar presentations
Software Testing. Quality is Hard to Pin Down Concise, clear definition is elusive Not easily quantifiable Many things to many people You'll know it when.
Advertisements

Annoucements  Next labs 9 and 10 are paired for everyone. So don’t miss the lab.  There is a review session for the quiz on Monday, November 4, at 8:00.
Test-Driven Development and Refactoring CPSC 315 – Programming Studio.
Developer Testing and Debugging. Resources Code Complete by Steve McConnell Code Complete by Steve McConnell Safari Books Online Safari Books Online Google.
Object Oriented Design An object combines data and operations on that data (object is an instance of class) data: class variables operations: methods Three.
API Design CPSC 315 – Programming Studio Fall 2008 Follows Kernighan and Pike, The Practice of Programming and Joshua Bloch’s Library-Centric Software.
Testing CPSC 315 – Programming Studio Fall Testing Testing helps find that errors exist Debugging finds and fixes them Systematic attempt to break.
Test-Driven Development and Refactoring Project 3 Lecture 1 CPSC 315 – Programming Studio Fall 2009.
Debugging CPSC 315 – Programming Studio Fall 2008.
Testing HCI Usability Testing. Chronological order of testing Individual program units are built and tested (white-box testing / unit testing) Units are.
Testing an individual module
Software Testing. “Software and Cathedrals are much the same: First we build them, then we pray!!!” -Sam Redwine, Jr.
CODING Research Data Management. Research Data Management Coding When writing software or analytical code it is important that others and your future.
Test Driven Development Derived from Dr. Fawcett’s notes Phil Pratt-Szeliga Fall 2009.
Dr. Pedro Mejia Alvarez Software Testing Slide 1 Software Testing: Building Test Cases.
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
Testing. What is Testing? Definition: exercising a program under controlled conditions and verifying the results Purpose is to detect program defects.
TESTING.
Chapter 12: Exception Handling
© 2012 IBM Corporation Rational Insight | Back to Basis Series Chao Zhang Unit Testing.
CMSC 345 Fall 2000 Unit Testing. The testing process.
1 Debugging and Testing Overview Defensive Programming The goal is to prevent failures Debugging The goal is to find cause of failures and fix it Testing.
PROGRAMMING IN VISUAL BASIC.NET VISUAL BASIC BUILDING BLOCKS Bilal Munir Mughal 1 Chapter-5.
Design and Programming Chapter 7 Applied Software Project Management, Stellman & Greene See also:
Describe the Program Development Cycle. Program Development Cycle The program development cycle is a series of steps programmers use to build computer.
Testing. 2 Overview Testing and debugging are important activities in software development. Techniques and tools are introduced. Material borrowed here.
Introduction CS 3358 Data Structures. What is Computer Science? Computer Science is the study of algorithms, including their  Formal and mathematical.
Unit Testing 101 Black Box v. White Box. Definition of V&V Verification - is the product correct Validation - is it the correct product.
Chapter 22 Developer testing Peter J. Lane. Testing can be difficult for developers to follow  Testing’s goal runs counter to the goals of the other.
Well-behaved objects Main concepts to be covered Testing Debugging Test automation Writing for maintainability Objects First with Java - A Practical.
What is Testing? Testing is the process of finding errors in the system implementation. –The intent of testing is to find problems with the system.
Week 14 Introduction to Computer Science and Object-Oriented Programming COMP 111 George Basham.
Software Engineering 2004 Jyrki Nummenmaa 1 BACKGROUND There is no way to generally test programs exhaustively (that is, going through all execution.
David Streader Computer Science Victoria University of Wellington Copyright: David Streader, Victoria University of Wellington Debugging COMP T1.
Dynamic Testing.
Unit Testing with FlexUnit
CS223: Software Engineering Lecture 18: The XP. Recap Introduction to Agile Methodology Customer centric approach Issues of Agile methodology Where to.
Today protected access modifier Using the debugger in Eclipse JUnit testing TDD Winter 2016CMPE212 - Prof. McLeod1.
Principles of Programming & Software Engineering
Software Testing.
Unit Testing.
Programming Studio, Fall 2017 Tanzir Ahmed
Regression Testing with its types
Test-Driven Development
Testing Tutorial 7.
Types for Programs and Proofs
Logger, Assert and Invariants
Coupling and Cohesion 1.
Defensive Programming
Topics Introduction to Repetition Structures
Testing and Debugging.
Reasoning About Code.
Introduction to Operating System (OS)
Chapter 13 & 14 Software Testing Strategies and Techniques
History, Characteristics and Frameworks
Design and Programming
Lecture 09:Software Testing
CSCE 315 – Programming Studio, Fall 2017 Tanzir Ahmed
Test-driven development (TDD)
Coding Concepts (Basics)
CSE 303 Concepts and Tools for Software Development
Automation of Testing in the Distributed Common Ground System (Army)
Automation of Testing in the Distributed Common Ground System (Army)
Test Case Test case Describes an input Description and an expected output Description. Test case ID Section 1: Before execution Section 2: After execution.
Exception Handling Imran Rashid CTO at ManiWeber Technologies.
CPSC 315 – Programming Studio
CS 240 – Advanced Programming Concepts
An Introduction to Debugging
Testing Slides adopted from John Jannotti, Brown University
Chapter 13 & 14 Software Testing Strategies and Techniques 1 Software Engineering: A Practitioner’s Approach, 6th edition by Roger S. Pressman.
Presentation transcript:

CPSC 315 – Programming Studio Spring 2017 Testing CPSC 315 – Programming Studio Spring 2017

Testing Testing helps find that errors exist Debugging finds and fixes them Systematic attempt to break a program that is working Unlike all other parts of software development, whose goal is to avoid errors Can never prove absence of errors Testing alone does not improve quality

Types of Testing Unit testing Component testing Integration testing Testing of a single class, routine, program Usually single programmer Testing in isolation from system Component testing Testing of a class, package, program Usually small team of programmers Integration testing Combined test of two or more classes, packages, components, or subsystems

Types of Testing (continued) Regression testing Repetition of previously tested cases to find new errors introduced System testing Executing software in final configuration, including integration with all other systems and hardware Security, performance, resource loss, timing issues

Other Testing Usually by specialized test personnel User tests Performance tests Configuration tests Usability tests Etc. We’re interested now in developer tests (and later in some usability tests)

Writing Test Cases First Helps identify errors more quickly Doesn’t take any more effort than writing tests later Requires thinking about requirements and design before writing code Shows problems with requirements sooner (can’t write code without good requirements) Foundation of Test Driven Development (we will get to this…)

Testing As You Write Code Boundary Testing Pre- and Post-conditions Assertions Defensive Programming Error Returns Waiting until later means you have to relearn code Fixes will be less thorough and more fragile

Boundary Testing Most bugs occur at boundaries If it works at and near boundaries, it likely works elsewhere Check loop and conditional bounds when written Check that extreme cases are handled e.g. Full array, Empty array, One element array Usually should check value and +/- 1 Mental test better than none at all

Preconditions and Postconditions Verify that routine starts with correct preconditions and produces correct postconditions Check to make sure preconditions met Handle failures cleanly Verify that postconditions are met No inconsistencies created Need to define pre-/postconditions clearly “Provable” software relies on this approach

Assertions Available in most languages assert.h (C/C++), Assert,AssertionError (Java) Way of checking for pre-/postconditions Helps identify where problem occurs Before the assertion e.g. usually in calling routine, not callee Problem: causes abort So, useful for testing for errors

Defensive Programming Add code to handle the “can’t happen” cases Program “protects” itself from bad data

Error Returns Good API and routine design includes error codes Need to be checked Exception handling (via try-catch) supported in many languages now Need to be clear about what exceptions are thrown, though

Systematic Testing Test of complete code pieces Test incrementally Test simple parts first Know what output to expect Verify conservation properties Compare independent implementations Measure test coverage

Test Incrementally Don’t wait until everything is finished before test Test components, not just system Test components individually before connecting them

Test Simple Parts First Test most basic, simplest features Finds the “easy” bugs (and usually most important) first

Know What Output To Expect Design test cases that you will know the answer to! Make hand-checks convenient Not always easy to do e.g. compilers, numerical programs, graphics

Verify Conservation Properties Specific results may not be easily verifiable Have to write the program to compute the answer to compare to But, often we have known output properties related to input e.g. #Start + #Insert - #Delete = #Final Can verify these properties even without verifying larger result

Compare Independent Implementations Multiple implementations to compute same data should agree Useful for testing tricky code, e.g. to increase performance Write a slow, brute-force routine Compare the results to the new, “elegant” routine If two routines communicate (or are inverses), different people writing them helps find errors Only errors will be from consistent misinterpretation of description

Measure Test Coverage What portion of code base is actually tested? Techniques to work toward this Following slides Tend to work well on only small/moderate code pieces For large software, tools help judge coverage

Logic Coverage Or, Code Coverage Testing every branch, every path through the code Can grow (nearly) exponentially with number of choices/branches Only suitable for small to medium size codes

Structured Basis Testing Testing every line in a program Ensure that every statement gets tested Need to test each part of a logical statement Easily catch basic and typo-like errors Far fewer cases than logic coverage But, also not as thorough Goal is to minimize total number of test cases One test case can test several statements

Structured Basis Testing (continued) Start with base case where all Boolean conditions are true Design test case for that situation Each branch, loop, case statement increases minimum number of test cases by 1 One more test case per variation, to test the code for that variation

Data Flow Testing Examines data rather than control Data in one of three states Defined – Initialized but not used Used – In computation or as argument Killed – Undefined in some way Variables related to routines Entered – Routine starts just before variable is acted upon Exited – Routine ends immediately after variable is acted upon

Data Flow Testing (continued) First, check for any anomalous data sequences Defined-defined Defined-exited Defined-killed Entered-killed Entered-used Killed-killed Killed-used Used-defined Often can indicate a serious problem in code design After that check, write test cases

Data Flow Testing (continued) Write test cases to examine all defined-used paths Usually requires: More cases than structured basis testing Fewer cases than logic coverage

Example Logic Coverage / Code Coverage Conditions: T T T if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Logic Coverage / Code Coverage Conditions: T T T Conditions: T T F Conditions: T F T Conditions: T F F Conditions: F T T Conditions: F T F Conditions: F F T Conditions: F F F Tests all possible paths

Example Structured Basis Testing Conditions: T T T Conditions: F F F if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Structured Basis Testing Conditions: T T T Conditions: F F F Tests all lines of code

Example Data Flow Testing Conditions: T T T Conditions: T F F if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Data Flow Testing Conditions: T T T Conditions: T F F Conditions: F T ? Conditions: F F ? Tests all defined-used paths Note: cond3 is independent of first two

Example Data Flow Testing Conditions: T T T Conditions: T F F if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Data Flow Testing Conditions: T T T Conditions: T F F Conditions: F T ? Conditions: F F ? Tests all defined-used paths Note: cond3 is independent of first two

Example Data Flow Testing Conditions: T T T Conditions: T F F if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Data Flow Testing Conditions: T T T Conditions: T F F Conditions: F T ? Conditions: F F ? Tests all defined-used paths Note: cond3 is independent of first two

Example Data Flow Testing Conditions: T T T Conditions: T F F if (cond1) { x = a; } else { x = b; } if (cond2) { y = x+1; y = x+2; if (cond3) { z = c; z = d; Data Flow Testing Conditions: T T T Conditions: T F F Conditions: F T ? Conditions: F F ? Tests all defined-used paths Note: cond3 is independent of first two

Test Case Design (If you don’t know the code) Boundary analysis still applies Equivalence partitioning Don’t create multiple tests to do the same thing Bad data Too much/little Wrong kind/size Uninitialized Good data Minimum/maximum normal configuration “Middle of the Road” data Compatibility with old data

Test Automation Should do lots of tests, and by-hand is not usually appropriate Scripts can automatically run test cases, report on errors in output But, we need to be able to analyze output automatically… Can’t always simulate good input (e.g. interactive programs) People cannot be expected to remain sharp over many tests Automation reduces workload on programmer, remains available in the future

Regression Testing Goal: Find anything that got broken by “fixing” something else Save test cases, and correct results With any modifications, run new code against all old test cases Add new test cases as appropriate Part of TDD (below)

Test Support Tools Test Scaffold Test Data Generators System Perturber Framework to provide just enough support and interface to test Stub Routines and Test Harness Test Data Generators System Perturber

Stub Routines Dummy object/routine that doesn’t provide full functionality, but pretends to do something when called Return control immediately Burn cycles to simulate time spent Print diagnostic messages Return standard answer Get input interactively rather than computed Could be “working” but slow or less accurate

Test Harness Calls the routine being tested Fixed set of inputs Interactive inputs to test Command line arguments File-based input Predefined input set Can run multiple iterations

Test Data Generators Can generate far more data than by hand Can test far wider range of inputs Can detect major errors/crashes easily Need to know answer to test correctness Useful for “inverse” processes – e.g. encrypt/decrypt Should weight toward realistic cases

System Perturbers Modify system so as to avoid problems that are difficult to test otherwise Reinitialize memory to something other than 0 Find problems not caught because memory is “usually” null Rearrange memory locations Find problems where out-of-range queries go to a consistent place in other tests Memory bounds checking Memory/system failure simulation

Other Testing Tools Diff tools Coverage monitors Data recorder/loggers Compare output files for differences Coverage monitors Determine which parts of code tested Data recorder/loggers Log events to files, save state information Error databases Keep track of what’s been found, and rates of errors Symbolic debuggers Will discuss debugging later, but useful for tests

Test-Driven Development Generally falls under Agile heading We will come back to what is meant by this A style of software development, not just a matter of testing your code Enforces testing as part of the development process

Test Driven Development Overview Repeat this process: Write a new test Run existing code against all tests; it should generally fail on the new test Change code as needed Run new code against tests; it should pass all tests Refactor the code

Test Writing First Idea is to write tests, where each test adds some degree of functionality Passing the tests should indicate working code (to a point) The tests will ensure that future changes don’t cause problems

Running Tests Use a test harness/testing framework of some sort to run the tests A variety of ways to do this, including many existing frameworks that support unit tests JUnit is the most well-known, but there is similar functionality across a wide range of languages

Test framework Specify a test fixture Basically builds a state that can be tested Set up before tests, removed afterward Test suite run against each fixture Set of tests (order should not matter) to verify various aspects of functionality Described as series of assertions Runs all tests automatically Either passes all, or reports failures Better frameworks give values that caused failure

Mock Objects To handle complex external queries (e.g. web services), random data, etc. in testing Implements an interface that provides some functionality Can be complex on their own – e.g. checking order of calls to some object, etc. Can control the effect of the interface

Example Mock Object Remote service Interface to authenticate, put, get Put and Get implementations check that authentication was called Get verifies that only things that were “put” can be gotten. As opposed to an interface that just returned valid for authenticate/put, and returned fixed value for get.

Successful Tests Tests should eventually pass You need to check that all tests for that unit have passed, not just the most recent.

Refactoring As code is built, added on to, it becomes messier Need to go back and rewrite/reorganize sections of the code to make it cleaner Do this on a regular basis, or when things seem like they could use it Only refactor after all tests are passing Test suite guarantees refactoring doesn’t hurt.

Refactoring Common Operations Extract Class Extract Interface Extract Method Replace types with subclasses Replace conditional with polymorphic objects Form template Introduce “explaining” variable Replace constructor with “factory” method Replace inheritance with delegation Replace magic number with symbolic constant Replace nested conditional with guard clause

Resources Many other books on testing, TDD, also Test-Driven Development By Example Kent Beck; Addison Wesley, 2003 Test-Driven Development A Practical Guide David Astels; Prentice Hall, 2003 Software Testing A Craftsman’s Approach (3rd edition) Paul Jorgensen; Auerback, 2008 Many other books on testing, TDD, also