+ All Categories
Home > Documents > Testing - University of Richmond

Testing - University of Richmond

Date post: 26-Oct-2021
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
121
Testing CMSC 240 All examples borrowed/modified from C++ Crash Course by Josh Lospinoso No Starch Press
Transcript
Page 1: Testing - University of Richmond

Testing

CMSC 240All examples borrowed/modified from C++ Crash Course by Josh Lospinoso

No Starch Press

Page 2: Testing - University of Richmond

Along the Way

• These slides are about unit testing and TDD

• But along the way, we’ll pick up:w Function objectsw Lambda expressionsw std::function

Page 3: Testing - University of Richmond

Unit Tests

w Unit tests verify that a focused collection of code (e.g., function or class) behave as intended§ Want these tests to isolate unit being tested

from its depend dependencies (though this may be difficult)

§ If tested unit depends on other unit, sometimes use mocks (fake objects) as stand in during tests• Mocks are only use for testing

Page 4: Testing - University of Richmond

Mocks

• Can be used to simulate fine-grained control over how the dependencies behave during test

• Can also test how unit is interacting with mocks, to ensure this is correct

• Can use mocks to simulate rare events (e.g., out of memory) by programming them to throw exceptions

Page 5: Testing - University of Richmond

Types of Unit Tests

• Integration Tests: Test a collection of units togetherw Can also refer to testing interactions

between software and hardwarew NOT a replacement for individual unit

tests, but complement them

Page 6: Testing - University of Richmond

Types of Unit Tests

• Acceptance Tests: Verify that software meets customer requirements

• Can be used to guide development• Once acceptance tests passed, software

is deliverable• These tests become part of code base,

so built-in protection against refactoring or feature regressionw Recall: breaking an old feature when

adding new

Page 7: Testing - University of Richmond

Types of Unit Tests

• Performance Tests: Just what it sounds likew Does code meet speed requirements?w Does code meet memory requirements?w Does code meet power consumption

requirements?• Typically have an idea where problems

will occur, but can’t be sure without testing

Page 8: Testing - University of Richmond

Types of Unit Tests

• Performance Tests• Can’t know whether optimizations are

working unless you measure after implementing

• Instrumentation: instrument code to provide relevant measuresw Also detect errors, log program execution

Page 9: Testing - University of Richmond

Intrumentation

• Often part of customer requirementsw E.g., procedure must execute in under

100ms and/or use less than 1MB of memory

w By making this part of code, can automate checks as further optimizations are implemented

Page 10: Testing - University of Richmond

Before a Working Example…

• Some C++ concepts that we’ll need for this example

w Function objectsw Lambda expressions

Page 11: Testing - University of Richmond

Function Objects

• One can make user-defined types callable or invocablew Done by overloading the function-call

operator operator()()• Such a type is called a function type

w Instances of a function type are function objects

• The function-call operator permits any combination of argument types, return types, and modifiers (except static)

Page 12: Testing - University of Richmond

Function Objects

• Why would you want to do this?w Might need to interoperate with code that

expects function objects § Many libraries, including stdlib use the

function call operator as interface to function-like objects (we’ll see one later)

§ Ex. Creating asynchronous task with std:asynch function, which accepts arbitrary function object that can execute on a separate thread

Page 13: Testing - University of Richmond

Function Objects

• Why would you want to do this?w The designers of std::asynch could

have required coder to expose a run method

w But function call operator allows generic code to use identical notation to invoke a function or a function-object

Page 14: Testing - University of Richmond
Page 15: Testing - University of Richmond

Output:

Page 16: Testing - University of Richmond

Lambda Expressions

• Lambda expressions construct unnamed function objects succinctlyw The function object implies the function

type§ Quick way to create a function object

• Can’t do anything a plain old function declaration can’t dow But in specific contexts can be very

convenient§ Declaring function objects can be verbose.

Lambda expressions much more succinct

Page 17: Testing - University of Richmond

Lambda Expressions: Usage

• Five componentsw captures: member variables of the function

objectw parameters: arguments required to invoke

function objectw body: function object’s codew specifiers: E.g., constexpr, noexceptw return type: just what you think

Page 18: Testing - University of Richmond

Lambda Expressions: Usage

• Syntax:

• [captures] (parameters) modifiers -> return type { body }

• Only capture and body requiredw So everything else is optional

• Each lambda component has direct analogue to part of function object…

Page 19: Testing - University of Richmond

Lambda Expressions: Usage

Page 20: Testing - University of Richmond

Lambda Expressions: Usage

captureparameters

bodyreturn type

specifiers

Page 21: Testing - University of Richmond

Lambda Parameters and Bodies

• Lambda expressions produce function objects, and thus are callablew You’ll often want the function object to

accept parameters upon invocation• Lamba expression body is just like a

function body – all parameters have function scope

• Declare lambda parameters and bodies using essentially same syntax as for functions

Page 22: Testing - University of Richmond

Lambda Parameters and Bodies

• Example:

• This lambda takes a single int x and uses it in the body to perform squaring

Page 23: Testing - University of Richmond

Lambda Example

Page 24: Testing - University of Richmond

Lambda ExampleDon’t be fooled. No differentthan typename T

Page 25: Testing - University of Richmond

Lambda ExampleDon’t be fooled. No differentthan typename T

Except you better provide a typethat can be invoked, because ofhow it’s used

Page 26: Testing - University of Richmond

Lambda Example

Output:

Page 27: Testing - University of Richmond

Lambda Example

Output:

Note that by declaring transform as a template function, youcan reuse it with any function object.

Page 28: Testing - University of Richmond

Generic Lambdas

• Generic lambdas are lambda expression templatesw For one or more parameter one specifies auto rather than a concrete type

w the auto types becomes template parameters§ Compiler will build a custom instantiation of the

lambda

Page 29: Testing - University of Richmond

Generic Lambdas

You better provide types Fn andT such that Fn that can be invoked on objects of type T

Page 30: Testing - University of Richmond

Generic Lambdas

generic lambda

Page 31: Testing - University of Richmond

Generic Lambdas

Output:

Page 32: Testing - University of Richmond

Lambda Captures

• Lambda captures inject objects into the lambdaw This can be used to modify behavior of

the lambdaw Declared within brackets []w Capture list before parameter listw Can contain any number of comma

separated values§ Which can then be used within lambda’s body

w Can capture by reference or value

Page 33: Testing - University of Richmond

Lambda Captures

to_count captured and can now be used within lambda’s body

lambda version of CountIf

Page 34: Testing - University of Richmond

Lambda Captures

Output:

Page 35: Testing - University of Richmond

Lambda Captures

Capture by reference

Note we are not declaringthese so no need for type

Page 36: Testing - University of Richmond

Lambda Captures

Output:

Page 37: Testing - University of Richmond

Working Example

• The setting: programming for autonomous vehiclew Code is complex and large (hundreds of

thousands of lines of code)w Entire solution consists of several binariesw Deployment requires uploading to car, a

time-consuming process§ Changing code, compiling, uploading, and

executing takes several hours per iteration

Page 38: Testing - University of Richmond

Working Example

• Entire software development broken into teamsw Each team responsible for a service

§ E.g., steering wheel control, audio/video, vehicle detection

w Services interact via a service bus§ Each service publishes to bus§ Services subscribe to other services as needed§ Service bus architecture

Page 39: Testing - University of Richmond

Working Example

• Your team: automonous braking servicew Service must determine whether collision

is about to happen, and if so, tell car to brake

w Service subscribes to two events:§ SpeedUpdate class: informs that the car speed

has changed§ CarDetected class: informs that another car

detected in front of you

Page 40: Testing - University of Richmond

Working Example

• Your team: automonous braking servicew Service must determine whether collision

is about to happen, and if so, tell car to brake

w Service publishes BrakeCommand to service bus when imminent collision detected

Page 41: Testing - University of Richmond

Working Example

Page 42: Testing - University of Richmond

Working Example

• You publish BrakeCommand using ServiceBus object that has a publish method

Page 43: Testing - University of Richmond

Working Example

• The Plan: w Expose observe method that subscribes

to SpeedUpdate and CarDetected events on the service bus

w Build AutoBrake class that keeps a reference to publish method of the service bus§ Say what? Reference to a method?

Page 44: Testing - University of Richmond

Working Example

• The Plan:

Page 45: Testing - University of Richmond

Working Example

Note that the arrow from Auto Braking Service to the Service bus does not mean that SpeedUpdate information is being sent to the Service bus, but rather that Automatic braking service relies on SpeedUpdate information from the Service bus.

Page 46: Testing - University of Richmond

Working Example

• Service integrates into car software like:

Page 47: Testing - University of Richmond

Working Example

Note auto_brake constructed with a lambda that captures areference to a ServiceBus. Details of how auto_brake decides to brake is hidden from other teams.

Page 48: Testing - University of Richmond

Working Example

• Service bus mediates all interservice communication

• Code passes any commands from the AutoBrake directly to the ServiceBusw Within event loop, a ServiceBus can pass SpeedUpdate and CarDetected objects to the observe method on your auto_brake

Page 49: Testing - University of Richmond

Implementing AutoBrake

• Conceptually simple: iterate among writing code, compiling production binary, uploading to car, and testing functionality manually

• Problems: will likely cause a lot of code (and potentially car) crashes

Page 50: Testing - University of Richmond

Implementing AutoBrake

• Better: write code, compile a unit-test binary, run on desktop environment

• This way, can iterate among steps quicklyw Once reasonably confident code works,

do manual test with live car• Unit-test binary will be console app

targeting desktop OSw In binary, run suite of tests that pass

specific inputs to an AutoBrake and assert it produces expected results

Page 51: Testing - University of Richmond

Requirements

• AutoBrake will consider car’s initial speed zero• AutoBrake should have configurable sensitivity

threshold based on number of seconds to impactw Must not be less than 1 second. Default is 5 secs

• AutoBrake must save car’s speed in between SpeedUpdate observations

• Each time AutoBrake observes CarDetectedevent, it must publish BrakeCommand if impact forecasted to occur in less that sens. thresh

Page 52: Testing - University of Richmond

Test-Driven Development (TDD)

• We’ll try implementing auto braking service using TDD

• So, the idea: if you’re going to be coding unit tests anyway, why not code them first?

• TDD or Not TDD: Something of a religious warw Like vim vs emacs, where prens go, big

endian vs little endian

Page 53: Testing - University of Richmond

TDD Advantages

• Key notion: write the code that tests a requirement before implementing solution

• Proponents claim:w Code is more modular, robust, clean, and

well designed• Good tests are excellent documentation• Good test suite is a working set of

examples that prevents regression

Page 54: Testing - University of Richmond

TDD Advantages

• Key notion: write the code that tests a requirement before implementing solution

• Great way to submit bug reportsw Found by failed unit testw Once fixed, stays fixed, because test and

code that fixes bug becomes part of the test suite

Page 55: Testing - University of Richmond

TDD: Red-Green-Refactor

• Red: First implement a failing testw Why? Make sure you’re actually testing

something!• Green: Implement code that makes the

test pass (no more, no less)• Refactor: restructure existing code

without changing functionalityw E.g., replace code with library, rewrite for

performance, elegancew If it breaks, test suite will tell you

Page 56: Testing - University of Richmond

Back to AutoBrake Example

• Need a skeleton class that implements interface without functionalityw Useful in TDD: you can’t write a test

without a shell of class you’re testing

Page 57: Testing - University of Richmond
Page 58: Testing - University of Richmond

Template type allowsfor programming generically against anytype that supports invocaton with a BrakeCommand.

Skeleton class has noinstructions in the bodyof methods. Because return type hereis void, don’t even needreturn statements

Page 59: Testing - University of Richmond

Note setter and gettermethods for collision threshold.Necessary to enforcethe class invariantfor collision threshold.Note only a getter forspeed.

Page 60: Testing - University of Richmond

Assertions

• Essential element of a unit test• An assertion tests that some condition

is metw If not met, test fails

What does constexpr mean?

Page 61: Testing - University of Richmond

Assertions

• Essential element of a unit test• An assertion tests that some condition

is metw If not met, test fails

What does constexpr mean? It instructs the compiler to evaluate the expression at compile time, if possible,

Page 62: Testing - University of Richmond

constexpr

What does constexpr mean? It instructs the compiler to evaluate the expression at compile time, if possible,

Page 63: Testing - University of Richmond

constexpr

Advantage: Significant impact on readability. Also potential significant improvement in runtime performance.

Page 64: Testing - University of Richmond

Assertions

• Essential element of a unit test• An assertion tests that some condition

is metw If not met, test fails

Page 65: Testing - University of Richmond

Requirement: Initial Speed 0

• Want to test that initial speed is 0• Write a function that creates an AutoBrake, “exercises” the class, and makes an assertion about result

Page 66: Testing - University of Richmond

Requirement: Initial Speed 0

• Construct AutoBrake with empty BrakeCommand publish functionw This unit test not concerned with publishing,

so give it simplest argument that will compilew When you don’t care about a dependence, can

just implement a stub: empty implementation that performs some innocuous task

Page 67: Testing - University of Richmond

Test Harness

• Test harness: code that executes unit tests

• Idea: create code that invokes unit tests, but handles failed assertions gracefullyw E.g., doesn’t crash on failed test(s)

Page 68: Testing - University of Richmond

Test Harness

• Test harness: code that executes unit tests

Page 69: Testing - University of Richmond

Test Harness

• What is with the strange declaration of run_test?

Page 70: Testing - University of Richmond

Recall: Function Pointers

• Declaring a function pointer is similar to declaring a function

Thanks Alex Allain: https://www.cprogramming.com/tutorial/function-pointers.html

Page 71: Testing - University of Richmond

Recall: Function Pointers

• Declaring a function pointer is similar to declaring a function

Page 72: Testing - University of Richmond

Test Harness

• Test harness: code that executes unit tests

Page 73: Testing - University of Richmond

Test Harness

• To make a unit-test program that will run all of the unit tests, place run_test inside the main function of a new program…

Page 74: Testing - University of Richmond
Page 75: Testing - University of Richmond
Page 76: Testing - University of Richmond
Page 77: Testing - University of Richmond
Page 78: Testing - University of Richmond

Requirement: Default Collision Threshold is 5

Page 79: Testing - University of Richmond

Requirement: Sensitivity Must Always be Greater Than 1

Page 80: Testing - University of Richmond

Requirement: Sensitivity Must Always be Greater Than 1

Page 81: Testing - University of Richmond

Requirement: Sensitivity Must Always be Greater Than 1

Page 82: Testing - University of Richmond

Requirement: Sensitivity Must Always be Greater Than 1

Requirement: Sensitivity Must Always be Greater Than 1

Page 83: Testing - University of Richmond

Mocking Dependencies

• Mock class (think ”mock up”): a special implementation that you generate for the purpose of testing a class that depends on the mockw That is, your class depends, say, on class foo. But you may not have the full foo implementation (perhaps it isn’t even coded yet)

w Use the mock to test interactions with your class

Page 84: Testing - University of Richmond

Aside: std::function

• std::function from <functional> header is a polymorphic container for callable objects

• In other words, a generic function pointerw You can store a static function, a function

object, or a lambda into a std::function

Page 85: Testing - University of Richmond

Declaring a function

• To declare a function you must provide a single template parameter containing the function prototype of the callable object

• std::function class template has many constructorsw Default constructor constructs a std::function in empty mode – it contains no callable object

Page 86: Testing - University of Richmond

Empty Functions

• If you declare a std::function with no contained object, “calling it” will throw a std::bad_function_call exception

Page 87: Testing - University of Richmond

Assigning a Callable Object to a Function

• Two ways: use the constructor or use the assignment operator of function

Page 88: Testing - University of Richmond

Example

• You can construct a function with any callable object that supports the function semantics implied by the template parameter of the function

Page 89: Testing - University of Richmond

Example

An array of std::function objects

Page 90: Testing - University of Richmond

Example

Page 91: Testing - University of Richmond

Runtime Overhead

• Using a function comes with a runtime overhead costw function might need to make a dynamic

allocation to store callable objectw Compiler has difficulty optimizing away function invocations, so often incur an indirect function call§ Requires additional pointer dereferences

Page 92: Testing - University of Richmond

Indirect Function Call?

• Direct function call: function call is made with a fixed address in instructionw For those in CS 301, jal to fixed address that has

been placed in the executable by the linker• Indirect function call: function call is made with

address of callee in a registerw Register is previously loaded either with fixed

address of function being called, or with a value fetched from somewhere else (e.g., memory or another register) where the function address has been stored

Page 93: Testing - University of Richmond

Indirect Function Call?

• Direct function call: will always call the same function

• Indirect function call: can call different functions, depending on what was loaded in register before call is madewThe indirection requires extra effort

Page 94: Testing - University of Richmond

We’re back: Mocking Dependencies

• AutoBrake has dependencies:w CarDetectedw SpeedUpdated

w Generic dependence on a publish object callable with a single BrakeCommand parameter

• Suppose you want to refactor the service busw Want to accept a std::function to

subscribe to each service

Page 95: Testing - University of Richmond

Mocking Dependencies

• Suppose you want to refactor the service busw Want to accept a std::function to

subscribe to each service

Page 96: Testing - University of Richmond

Mocking Dependencies

• IServiceBus is an interfacew So no need to know implementation detailsw And you can do your own wiring into the

service bus

Recall that using keyword is like the C language typedef

Page 97: Testing - University of Richmond

Mocking Dependencies

• Suppose you want to refactor the service busw Want to accept a std::function to

subscribe to each service• A problem: How do you test AutoBrake

in isolation?w Using the real production bus is not testing

anymore, but integration§ And definitely not an easily configurable,

isolated unit test

Page 98: Testing - University of Richmond

Mocking Dependencies

• But, you don’t depend on implementation: you depend on the interface!

• So create a mock class that implements the IServiceBus interface, and use that within AutoBrakew AutoBrake interacts with the mock, not

the production service bus

Page 99: Testing - University of Richmond

Mocking Dependencies

• AND because you have complete control over the mock and it’s a unit-test-specific class, you can do just about anything you want with itw Can record arbitrarily detailed info about

how the mock gets called by AutoBrake§ E.g., number of times the mock is called and

with which parametersw Can perform arbitrary computation in the

mock

Page 100: Testing - University of Richmond

Mocking Dependencies

• You have complete control over the inputs and the outputs of the dependencies of AutoBrake. E.g., …w How does AutoBrake handle the case

where the service bus throws an out-of-memory exception inside of a publish invocation? (You can test that!)

w How many times did AutoBrake register a callback for SpeedUpdates? (Can test that too!)

Page 101: Testing - University of Richmond
Page 102: Testing - University of Richmond

this publish records the number of time publish was called and the last command that was published

Page 103: Testing - University of Richmond

One Note:

• Mocks are very useful, but for this example, if you refactor the service bus, you’ll have to refactor your unit tests as wellw No way around that, unless the interface to

the service bus doesn’t change

Page 104: Testing - University of Richmond

Unit Testing and Mocking Frameworks

• Unit-testing frameworks make unit testing easier, just as IDEs can help make coding easierw Provide commonly used functions and the

scaffolding necessary to tie tests into a user-friendly program

w Functionality to help create consice, expressive tests

Page 105: Testing - University of Richmond

The Catch Unit-Testing Framework

• Catch Unit Testing Framework: One of three described in your text

• Very straightforward• Written by Phil Nash• Available at

https://github.com/catchorg/Catch2/• Header only library

w So you can download the single-header version and #include in each unit-testing translation unit

Page 106: Testing - University of Richmond

Catch

• Easiest way to use thisw Download single catch.hpp header file

§ https://raw.githubusercontent.com/catchorg/Catch2/v2.x/single_include/catch2/catch.hpp

w Put it in your project directoryw Be sure to #include it in unit test code

Page 107: Testing - University of Richmond

Catch

• Defining an entry pointw Provide your test binary’s entry point with #define CATCH_CONFIG_MAIN

w That’s it: Within the catch.hpp header file, it looks for CATCH_CONFIG_MAIN preprocessor definition

w When found, Catch will add a main function (so you don’t have to)

w Automatically grabs all unit tests you have defined and wraps them in a test harness

Page 108: Testing - University of Richmond

Catch

• Building: just build the executable as usualw E.g., if the code below is listing_10_30.cpp, then just make listing_10_30

w Note it has no main method

Page 109: Testing - University of Richmond

Catch

• Running listing_10_30 gives

Page 110: Testing - University of Richmond

Recall…

• Earlier, we defined separate functions for each unit test

• Passed a pointer to each function as the first parameter to run_test

• Passed name of the test as the second parameterw Which is redundant if you named unit test

function well• Implemented an assert function for

each unit test

Page 111: Testing - University of Richmond

Catch

• Catch does all of that implicitly• For each unit test, use TEST_CASE

macro and Catch does all of the integration for you

Page 112: Testing - University of Richmond

Catch

• The Catch entry point here detects that one unit test called “AutoBrake” has been declared.

• It also provides a warning that we have not made any assertions

Page 113: Testing - University of Richmond

Catch: Making Assertions

• Catch comes with a built-in assertion, with two distinct families of macros w REQUIRE: will fail a test immediatelyw CHECK: will allow test to run to completion,

but still cause a failure§ Useful if a group of related assertions can help

lead the programmer toward a bugw Also, macros for assertions that should be

false§ REQUIRE_FALSE

§ CHECK_FALSE

Page 114: Testing - University of Richmond

Catch: Making Assertions

• Usage: wrap a Boolean expression with REQUIRE macrow If expression evaluates to false, assertion

failsw You provide assertion expression that

evaluates to true if assertion passes, false if it doesn’t

• Syntax: REQUIRE(assertion-expression);

Page 115: Testing - University of Richmond

Example: initial_speed_is_zero

Page 116: Testing - University of Richmond

Whole Enchilada

The whole thing

Page 117: Testing - University of Richmond

Whole Enchilada

Setup code. Automaticallyreinitialized and includedin each SECTION

Page 118: Testing - University of Richmond

Whole Enchilada

How you implementfloating point assertions

Page 119: Testing - University of Richmond

Sample Output

Page 120: Testing - University of Richmond

Sample Output

Page 121: Testing - University of Richmond

Testing: Summary

• Unit tests• Mocks• Test-driven development• Assertions• Mocks• Unit-testing frameworks


Recommended