Top Banner
Testing, part 2 Course notes for CEN 4010
32

Testing, part 2

Jan 21, 2016

Download

Documents

Almira

Testing, part 2. Course notes for CEN 4010. OO Testing. Testing objects in isolation Inheritance Aggregation Objects as parameters State Destruction Self diagnosis. Testing Objects in Isolation. Data Members Allowed range vs. Disallowed range Boundary values (v-1, v, v+1) - PowerPoint PPT Presentation
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Testing, part 2

Testing, part 2

Course notes forCEN 4010

Page 2: Testing, part 2

OO Testing

Testing objects in isolationInheritanceAggregationObjects as parametersStateDestructionSelf diagnosis

Page 3: Testing, part 2

Testing Objects in Isolation

Data Members Allowed range vs. Disallowed range Boundary values (v-1, v, v+1) Can data members be accessed directly?

Operations Arguments

Allowed rangeBoundary valuesEstablish equivalence partitions

Page 4: Testing, part 2

Testing Objects in Isolation

Operations (continued) Construction

Proper initialization of all data membersProper defaults if value not specified

DestructionProper deallocation of memory

Set & Get operationsIs operation doing defensive checks to catch

invalid data?

Page 5: Testing, part 2

Inheritance: Overview

Liskov Substitution Principle If an object of type D can be substituted for

an object of type B, and program P’s behavior is unchanged, then D is a subtype of B.

Everything that is true of each superclass is also true for the subclass.

You cannot NOT inherit data members or member functions from a superclass. You cannot NOT inherit changes made to a

superclass!

Page 6: Testing, part 2

The Fragile Superclass Problem

Consider class CheckingAccount which is derived from class InterestBearingAccount:class InterstBearingAccount{public: float iRate; float GetBalance() const; //constraint: balance >= $0.00};

class CheckingAccount : public InterestBearingAccount{public: float FutureValue(UINT NoYears) {

return pow(GetBalance(), ....... ); }

What happens to FutureValue()if GetBalance()can return a negative number?

Page 7: Testing, part 2

Order of Testing Inheritance

Across Classes: Test superclasses before subclasses.

The superclass is the foundation for the subclass! Test superclass functions visible through

subclass Test functions over-ridden in derived class.

Within a Derived Class: Test object construction for proper initialization

& assignment of data members.superclass constructorembedded class construction

Test new functions in derived class.

Page 8: Testing, part 2

Testing Abstract Base Classes

Consider:class Employee { public: //...other member functions... virtual Paystub GeneratePay( ) = 0; //must define in subclasses};

class SalariedEmployee : public Employee{ public: //... Paystub GeneratePay( ) {....; }};

How do I test the abstract class Employee?

Page 9: Testing, part 2

Testing Abstract Base Classes

Option 1: Temporarily convert Employee to a

concrete class and test it in isolation:class Employee

{ public: //... void OtherFunction( ); virtual Paystub GeneratePay( ) //=0{::Messagebox(“EmployeePay()”...) ; ...;}};

Employee emp(......); //create instance of formerly abstract classemp.GeneratePay( ); //test NON-PURE member functionemp.OtherFunction( ); //test other Employee member functions....

Page 10: Testing, part 2

Testing Abstract Base Classes

Option 2: Temporarily convert Employee to a concrete

base class and test it in context:class Employee { public: //... virtual Paystub GeneratePay( ) //=0

{::Messagebox(“EmployeePay()”...) ; ...;}};

SalariedEmployee sEmp(......); //SalariedEmployee::GeneratePay commented-out

sEmp.GeneratePay( ); //test NON-PURE member function of base class.

Page 11: Testing, part 2

Which Subclass Functions Must Be Tested?

Consider two classes, Base and Derived. Base has function nochange() and overridden(). Derived overrides and redefines the function

overridden().

Must test Derived:overridden( )—it’s new code. Must I test Base::nochange( )?

Yes, if Base::nochange( ) calls or uses a return value from overridden( ), [which may now actually be the Derived::nochange( ) function using the Derived::overridden( ) function.]

Derived::overridden( ) may return a superset of values beyond those returned by Base::overridden().

Base

nochange()overridden()

Derived

overridden()

Page 12: Testing, part 2

Reusing base class tests in a derived class?

Base::overridden( ) and Derived::overridden( ) are two different functions.

But their sets of test requirements will overlap. You only need to write new tests for those

Derived::overridden( ) requirements that are not satisfied by the Base::overridden( ) tests.

Notes: You have to apply the Base::overridden( ) tests to objects of

class "derived". The test inputs may be the same for both classes, but the expected results might differ in the Derived class.

WHY?

Page 13: Testing, part 2

Testing Overridden Functions

Look for: Differences in argument ranges

Subclass function may have a narrower range than overridden superclass function.

Differences in return valuesIf subclass returns a larger range, existing

programs may not behave properly—may die!

Proper class::function is calledEspecially important in C++

• (static type != dynamic type)

Page 14: Testing, part 2

Testing: Aggregation

Test Order From containing class to contained classes.

Will require writing stub classes/functions to test containing classes.

From contained classes to containing class. Will require writing driver functions to test contained classes.

Protocol Test Test direction of any function protocols

Does embedded object know it is contained? Does embedded object’s behavior change because it is

contained? Do aggregate and embedded object converse bi-directionally? Does aggregate regard embedded objects as mere servers?

Page 15: Testing, part 2

Testing: Aggregation

State Test What are dependencies of aggregate’s state upon the

embedded objects’ states? Derived from STD’s.

Test that each state for aggregate is properly mapped into each embedded object.

E.g. if the Vehicle is in the ON state, is each embedded object also ON, or at least ENABLED?

Test that each state for each embedded object is properly mapped into the aggregate’s state.

E.g. if the Headlights are broken, is the Vehicle still functional in a degraded mode?

Page 16: Testing, part 2

Aggregate as an Agent, or Broker

Suppose a class ApplianceServicer wants to check the status of the OverHeadProjector’s PowerSupply. Should OverHeadProjector have a member function: GetPowerSupply( )?class OverHeadProjector{public:

//.......PowerSupply * GetPowerSupply( );

private:Fan f;Base b;FocusingLens fl;PowerSupply* ps;

};

Page 17: Testing, part 2

Aggregate as a Broker

If we provide the GetPowerSupply( ) function in OverHeadProjector, then we allow ApplianceServicer to have unrestricted access to PowerSupply.

In this scenario OverHeadProjector is acting as a broker.

OverHeadProjector

PowerSupply

Light

FanBase

Lens

GetPowerSupply( )

ApplianceServicer

Page 18: Testing, part 2

Aggregate as a Broker

Drawbacks: requestor objects can change state of member object

without the containing object knowing this. the requestor could delete the member object

without the containing object knowing this. (The double delete of the memory might crash the application.)

The broker object reveals its implementation when it “matches-up” the requestor and the member object.

Advantages: Aggregate maintains a simplified interface.

Page 19: Testing, part 2

Aggregate as an Agent

If OverHeadProjector acts as an “agent” for the PowerSupply, it provides a surrogate interface(e.g., GetPowerSupplyStatus() ) to a requestor object.

Requestor never interfaces with PowerSupply directly.

PowerSupply

Light

FanBase

Lens

ApplianceServicer

Status()OverHeadProjectorGetPowerSupplyStatus( )

Page 20: Testing, part 2

Aggregate as an Agent

Drawbacks: Aggregate object must provide a surrogate interface

for each member object function to be “exported”. Performance may suffer. Maintenance is complicated as the member objects

evolve new member functions.Advantages:

Aggregate object maintains complete control of member object (no multiple deletes; change of state).

Member objects are fully encapsulated and hidden (implementation is not visible).

Page 21: Testing, part 2

Testing: Aggregation

Aggregate as Broker Test that embedded objects notify

aggregate when they are destroyed.Requires embedded object constructor that

takes “owner” as argument.

Test that embedded objects provide interfaces for aggregate to determine their state. E.g. “changed by requestor”, “disabled”,

“enabled”

Page 22: Testing, part 2

Testing: Aggregation

Aggregate as Agent Test that each function exported from

embedded object has been identified and can be called regardless of aggregate’s state.E.g. I should be able to ask for the

PowerSupply’s state even if the aggregate does not yet have a PowerSupply.

Page 23: Testing, part 2

Static & Dynamic Types: “Slicing”

Consider the following classes: ....and the following function:

class Window void printNameAndDisplay (Window w){public: {

const char * name( ) const; cout << w.name( );virtual void display( ) const; w.display( );

}; }

class BorderedWindow : public Window{public:

virtual void display( ) const;}; What happens when we call this function with a BorderedWindow

object?

BorderedWindow bw;printNameAndDisplay(bw);

[after MEYE92]

Page 24: Testing, part 2

“Slicing”: Pass-by-Value

Parameter w is constructed as a Window object (note: it is passed by value).

All the information specific to BorderedWindow is sliced off parameter w.

Inside printNameAndDisplay( ), w will always act like a Window object.

The call to display( ) will always call Window.display( ), not the BorderedWindow.display( ) function—despite the fact that display( ) is virtual!

Page 25: Testing, part 2

“Slicing”: through Assignment Consider:

class String

{ //......};class Filename: public String{ //...};

If we have a String s and a Filename f, what happens in the following code?s = f ;

The Filename portion of f is sliced off, and the String portion of f is assigned to s.

[KOEN96]

Page 26: Testing, part 2

Representing State

Example 1: A Person object can pass through the marital

states: Single, Engaged, Married, Divorced, Widowed.

How should we represent marital state in a Person object?

Example 2: Water can exist in three common physical states:

Solid, Liquid, Vapor. How should we represent physical state in a Water

object?

Page 27: Testing, part 2

State: Enumerated Attributesclass Person{public:

enum maritalState {SINGLE, ENGAGED, MARRIED, DIVORCED, WIDOW};.....GoOutWithOppositeSex();GoShopping();PayBills();....

};

Valid technique if normal Person-functions do not experience “gross” changes in behavior as Person changes maritalState.

Otherwise, you will die on all the switch (maritalState).... statements.

Page 28: Testing, part 2

Testing: Enumerated States

Use State Transition Diagrams.Select object & the subset of class states it will

transit. Different construction different initial states.

Test transition of object into and out of each selected state.

Test for proper behavior of each function in each selected state.

Attempt improper behavior in each selected state.

Page 29: Testing, part 2

Testing Object Destruction:Object Ownership

Object Ownership Test that each object has an “owner”

who destroys it appropriately. Test that objects which commit suicide

do so properly.The method of suicide must conform to the

method of object construction.

Page 30: Testing, part 2

Testing Object Destruction:Clean-up Functions

Verify as appropriate that an object: Cleans-up itself into a state in which its

destructor can safely be invoked.E.g. a collection may need to direct its

components to store themselves in a database before it (and they) are destroyed.

Propagates the “clean-up” to other objects under its control before they are destroyed.

Has client objects which properly observe and invoke its clean-up protocol.

Page 31: Testing, part 2

Self diagnosis: Is_Valid( )

class BusinessObject{public:

virtual boolean Is_Valid() const = 0;....

};

class GeneralInvoice : public BusinessObject

{private:Date dt; String name; float Amount;

public:virtual boolean Is_Valid() const { return (name.Is_Valid() && dt.Is_Valid() && Amount <1000) }

};

Defensive technique for detecting internal inconsistencies.

interface BusinessObject{ boolean Is_Valid();

....}

class GeneralInvoice implements BusinessObject{private Date dt; private String name; private float Amount;

public boolean Is_Valid( ){ return (name.Is_Valid() && dt.Is_Valid()

&& Amount <1000) }

}

Page 32: Testing, part 2

Self diagnosis: Dump( )

Service function to force dump of instance variables.class BusinessObject{public:

virtual void Dump( ) const = 0;....

};

class GeneralInvoice : public BusinessObject{private:

Date dt; String name; float Amount; public:

virtual void Dump() const { DumpStream ds(“MyDumpStreamFile”);

ds << “GeneralInvoice” << objID << “Date:” << dt <<“Name:” <<name << “Amount:” << Amount << endl;

}};