Hypothesis testing – mean differences between populations Part 2.
Testing, part 2
description
Transcript of Testing, part 2
Testing, part 2
Course notes forCEN 4010
OO Testing
Testing objects in isolationInheritanceAggregationObjects as parametersStateDestructionSelf diagnosis
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
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?
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!
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?
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.
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?
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....
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.
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()
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?
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)
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?
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?
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;
};
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
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.
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( )
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).
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”
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.
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]
“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!
“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]
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?
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.
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.
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.
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.
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) }
}
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;
}};