How To Use
 All Modules Pages
SimulatedObjects - implementation and control

Modules

 C++ code: Definition of base class SimulatedObjectBase
 
 C++ sample: Implementation of a simulated object
 
 C++ sample: Testcase with oERROR + AFTER_N_CALLS_ACTIVE_ONCE
 
 C++ sample: Testcase with oBLOCKING, oSYNC, _ContinueExecution
 
 C++ sample: Testcase with option values, DumpAllOptions, AutoRestoreOptions
 

Detailed Description

Overview

Why simulated objects?

Within a typical test environment the system under test (SUT) usually needs some communication partners within its runtime environment. These communication partners are often simulated, e.g. instead of using the real components simple fake objects are used, which enable the following testing possibilities:

This page gives a short overview about the possibility to implement a simulated object using base class RegisteredSimulatedObject / SimulatedObjectBase and about controlling behaviour by setting appropriate Options.

A more detailed description can be found within Info about Simulated Objects.

Context diagram - simulated objects embedded within test framework

OverviewSimulatedObject.png

Implementing a simulated object

Derive from RegisteredSimulatedObject

Example:

class MySimulatedObject : public TTB::RegisteredSimulatedObject
{
public:
MySimulatedObject(const std::string& in_name)
: RegisteredSimulatedObject(in_name, TTB_CLASS_NAME)
{}
void DoSomething(int in_val, double& out_val)
{
out_val = 3.14 * in_val;
TTB_METHOD_CALL1("in_val=" << in_val);
}
SomeErrorType DoSomethingElse(double in_val)
{
return TTB_METHOD_CALL_RET2(SomeErrorType, "in_val=" << in_val);
}
};

Use implementation macros TTB_METHOD_CALLx

Available implementation macros Purpose
TTB_METHOD_CALL() automatically deduces method name and name of your simulated object; if not specified otherwise within options then writes entry to TestEvents which has to be verified via a call to macro TTB_EXP().
Sample entry within TestEvents: "DoSomething (SimObjectA)"
TTB_METHOD_CALL1(stringStreamExpression) same as TTB_METHOD_CALL, allows output of additional information (e.g. param values)
Sample entry within TestEvents: "DoSomething in_val=42 (SimObjectA)"
TTB_METHOD_CALL2(stringStreamExpression, stringFuncBody) same as TTB_METHOD_CALL1, additionally allows call of a user defined lambda expression making arbitrary manipulations and finally returning a string which is used for output. With active option oBLOCKING the lambda expression is called with delay at the time when the blocked function is continued!
TTB_METHOD_CALL_RET1(ReturnType) same as TTB_METHOD_CALL, but returns an error when option oERROR is active. To allow a generic creation of an error you have to supply the following function within namespace TestToolBox:
      std::string MakeReturnValue(
          ReturnType&                 out_retVal,
          bool                        in_simulateFailure,
          std::string const &         in_methodName,
          SimulatedObjectBase const * in_pObject);
This function willl be called by macro TTB_METHOD_CALL_RET1 to return an appropriate error. More details are available within C++ sample: Implementation of a simulated object.
TTB_METHOD_CALL_RET2(ReturnType, stringStreamExpression) same as TTB_METHOD_CALL_RET1, allows output of additional information (e.g. param values)
TTB_METHOD_CALL_RET3(ReturnType, stringStreamExpression, stringFuncBody) same as TTB_METHOD_CALL_RET2, additionally allows call of a user defined lambda expression making arbitrary manipulations and finally returning a string which is used for output. With active option oBLOCKING the lambda expression is called with delay at the time when the blocked function is continued!

Possible customization:
If you have requirements exceeding the possibilities of the predefined macros you can instead use the underlying method implementation _MethodCall() or build your own variation of it.

Controlling behaviour by setting boolean options

You can set an arbitrary instance specific option by calling

or you can set a global option by calling

The general parameter list of both methods is

std::string const & in_option,
std::string const & in_scope = Option::ALL,
OptionType::Enum in_optionType = OptionType::PERMANENTLY_ACTIVE,
int in_numRemainingCalls = 0

Userdefined options

You can define your own boolean option (e.g. "ChooseAlgorithm_X") by simply writing:

SimObject("MySimObjectB")->_SetOption("ChooseAlgorithm_X");

Within some method implementation of your simulated object you can check whether this option is set:

...
if (_IsOptionSet("ChooseAlgorithm_X"))
{
    ...
}
...

As the options are defined within the text based maps built into SimulatedObject framework no other definitions are needed. The match between location of definition and location of usage is found by a simple string match. There is no need to define any interfaces to reach the internals of your simulated object.

Predefined options - oERROR, oSILENT, oSYNC, ...

There is a list of predefined options which are automatically used within TTB_METHOD_CALL macros.

Predefined Option Purpose
Option::oBLOCKING halt execution until explicit trigger for continue
Option::oERROR return error; works for macros TTB_METHOD_CALL_RET1-3
Option::oOBJECT_NAME use object name when writing to TestEvents
Option::oSILENT suppress generation of TestEvent; when set to false you have to verify the call within your test script (e.g. via TTB_EXP("DoSomething ")
Option::oSYNC generate sync event for which you can wait within test case code

Examples with often used predefined options:

// All simulated objects shall write their name
TTB::TheGlobalOptions()->Set(TTB::Option::oOBJECT_NAME);
// All instances of class MySimulatedObject shall create
// a sync event when method DoSomething() is called
TTB::TheGlobalOptions()->Set(TTB::Option::oSYNC,
"MySimulatedObject::DoSomething");
// When method "DoSomethingElse" of the simulated object with
// name "MySimObjectA" is called for the 3rd time from now on
// then an error shall be returned. All following calls
// shall succeed.
SimObject("MySimObjectA")->_SetOption(TTB::Option::oERROR,
"DoSomethingElse", AFTER_N_CALLS_ACTIVE_ONCE, 3);

Scope of an option - 'SomeClass::SomeMethod', ...

The macro TTB_METHOD_CALL and all of its variants check for the value of an option by calling SimulatedObjectBase::_IsOptionSet (someOption, "MyMethodName"). The search for an option entry is performed according to the following sequence:

The search stops when the first entry is found. If no entry is found the option is not set, i.e. the option value is false.

Knowing this search algorithm you can choose an appropriate scope to address the reaction you need.

Option types - PERMANENTLY_ACTIVE, AFTER_N_CALLS_ACTIVE_ONCE, ...

Option types Purpose
NOT_ACTIVE the option is explicitly switched off;
the search within other scopes (see above) stops here.
PERMANENTLY_ACTIVE the option is simply switched on and remains active until explicitly being switched off.
ACTIVE_ONCE The option is active for the next call to Options::IsSet("someOption") and then automatically is switched off for all further calls.
Within the context of a SimulatedObject this means that the TTB_METHOD_CALL macro which checks some option (e.g. whether to return an error) or the explicit call to SimulatedObjectBase::_IsOptionSet("someOption") will detect the option only for the next call.
AFTER_N_CALLS_PERMANENTLY_ACTIVE the option is switched on when from now on the N-th call to Options::IsSet("someOption") occurs.
AFTER_N_CALLS_ACTIVE_ONCE the option is switched on when from now on the N-th call to Options::IsSet("someOption") occurs. From (N+1)-th call on the option is automatically switched off
WAS_ACTIVE this option is internally used to be able to ask via Option::WasSet() for the last status of Options::IsSet("someOption"); technically Options::IsSet() may change the status of the option and Options::WasSet() does not.
VALUE this option is internally used to mark a value option, which is set via Options::SetValue() or SimulatedObjectsBase::_SetOptionValue(). For more details see next section.

Setting internal values of arbitrary type

Besides boolean options as described above your simulated object may have to work with other values of arbitrary type. You can influence those internally used values by setting "option values" or by specifying them on command line.

Using option values - _SetOptionValue, _GetOptionValue<>

You can define an option value by simply writing:

    // Set globally defined value
    TTB::TheGlobalOptions()->SetValue("xVal", "15.08");

    // Set specific value for a specific method of a specific object
    SimObject("SimObjectA")->_SetOptionValue("xVal", "3.14", "DoSomething");

Within some method implementation of your simulated object you can access the configured value:

...
double xVal = _GetOptionValue<double>("xVal", TTB_FUNC_NAME);
...

If the option value was not set before then _GetOptionValue<>() will return a default constructed value of required type. Numeric types will therefore be initialized with 0. As an alternative you can explicitly check for existence of the option via method _IsOptionSet("xVal").

For a full example see C++ sample: Testcase with option values, DumpAllOptions, AutoRestoreOptions

Read values from command line - GetCommandLineOptionVal<>

When calling your test executable you can specify a command line parameter:

MyTestExecutable.exe -- -xVal 6.28

Within some method implementation of your simulated object you can access the command line value:

...
double xVal = TTB::TheEnvironment()->GetCommandLineOptionVal<double>_GetOptionValue<double>("-xVal");
...

General services

Check current option settings - DumpAllOptions

If you are in doubt which boolean or numeric options are active within your test case you can simply dump all global and object specific options with a single call to DumpAllOptions():

    TTB_CMD1(TTB::DumpAllOptions, TTB::CTX_TEST_EVENT);
    TTB_EXP("GlobalOptions");
    TTB_EXP("    objectName:all: PERMANENTLY_ACTIVE");
    TTB_EXP("    xValall: VALUE 15.08");
    TTB_EXP("RegisteredSimulatedObjects");
    TTB_EXP("SimObjectA");
    TTB_EXP("    xValDoSomething: VALUE 3.14");
    TTB_EXP("    xValDoSomethingElse: VALUE 8.99");
    TTB_EXP("SimObjectB");
    TTB_EXP("    xValall: VALUE 10.01");

Hint: Omitting the parameter CTX_TEST_EVENT or specifying CTX_INFO instead releases you from verifying the returned settings within your test. The output will still be visible within your test protocol.

Automatically restore options - AutoRestoreOptions

Typically for executing a specific test situation you may want to temporarily change some option setting. To automatically switch back to the original option settings you can use class AutoRestoreOptions which stores the current settings at time of construction and restores them within its destructor. Within test case you can simply write:

...
{
    TTB::AutoRestoreOptions whenLeavingScope;

    // Change options
    TTB::TheGlobalOptions()->SetValue("xVal", "15.08");
    SimObject("SimObjectC")->_SetOption(TTB::Option::oERROR, "CalculateSomething");

    // perform your test actions
    ...
} // restore original option settings
...

Useful base class methods - _Trigger, _ContinueExecution, ...

Besides the setting and resetting of boolean and numeric options there are a couple of methods within base class SimulatedObjectBase which may be of special interest:

Method Purpose
_ContinueExecution (
std::string const & in_methodName)
Continue the execution of a method call which has been blocked.
_Trigger (
int in_hint = 0)
General purpose method to trigger something. Base implementation does nothing.
Derived classes may override this method and use the call e.g. to recheck all set options and prepare some internal data used for inter working within test. The call may also cause a direct test specific interaction with the test environment or the test object.
_MethodCall (
std::string const & in_methodName, std::string const & in_callInfo = "", StringFunc in_func = StringFuncEmpty)
Generic method execution with support for writing to TestEvents, generating sync events and blocking.
is internally used by macros TTB_METHOD_CALLx; the source code may be a good starting point for specific method implementations when TTB_METHOD_CALLx macros do not fulfill all your needs.

For a full description of class SimulatedObjectBase see C++ code: Definition of base class SimulatedObjectBase.

Code samples