Parameterized Test Units: Difference between revisions
No edit summary |
|||
(4 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
__NOTOC__ | |||
Stride provides an easy way for passing parameters from the [[STRIDE Runner | Stride Runner]] on the host to the test code executing on the target device. | |||
Pass parameters via the command line to your constructor | |||
stride .. --run=MyTest(42) | |||
Pass parameters using a name-value collection | |||
stride .. --run="MyOtherTest(/path/to/file.ini)" | |||
This allows customization of the test behavior at runtime and is useful when you want to run the same test scenario with different sets of input data, as described by [http://xunitpatterns.com/Parameterized%20Test.html this pattern]. | |||
There are two ways you could pass parameters: | |||
* as constructor arguments | |||
* as a name-value collection | |||
== | == Constructor Arguments == | ||
Passing parameters as constructor arguments is very simple and natural, however could be quite challenging when you need to pass more than a couple. | |||
=== How to use in your test code === | |||
To use parameters passed as constructor arguments you need to implement a public constructor in your C++ Test Unit (or extend the Initialization function of your C-Class Test Unit) with an argument list of [http://en.wikipedia.org/wiki/Null-terminated_string C-string] and numeric (integer or double) types: | |||
;C++ Test Unit | |||
<source lang=cpp> | <source lang=cpp> | ||
//MyTest.h | |||
#include <srtest.h> | #include <srtest.h> | ||
class MyTest | class MyTest | ||
{ | { | ||
public; | public; | ||
MyTest(int nParam, const char* szParam) | MyTest(int nParam, const char* szParam, double dParam) | ||
: m_nParam(nParam) | |||
, m_dParam(dParam) | |||
{ | { | ||
strncpy(m_szParam, szParam, MAX_VALUE_LEN); | |||
strncpy(m_szParam, szParam, | |||
} | } | ||
Line 110: | Line 44: | ||
... | ... | ||
private: | private: | ||
// typically, you will store parameter values into member variables for use by the member test methods | |||
int m_nParam; | int m_nParam; | ||
char m_szParam[ | char m_szParam[MAX_VALUE_LEN]; | ||
double m_dParam; | |||
}; | }; | ||
Line 118: | Line 54: | ||
#endif | #endif | ||
</source> | </source> | ||
'''NOTE:''' ''Don't declare more ''than one'' public constructor. This is typically not a problem for non-parameterized test classes, as a common [http://en.wikipedia.org/wiki/Nullary_constructor default constructor] is what's needed. Often you will begin with a non-parameterized test class and add the parameterization later as your testing gets more sophisticated. A common mistake here is to add a second public parameterized constructor to the class in addition to the original default constructor; this is perfectly legal in C++, but will not give you the desired result.'' | |||
'''NOTE:''' ''Don't set default values for your constructor arguments. In the case of Stride, each test class is instantiated dynamically on demand by the harnessing code. The harnessing code does not know at build time whether constructor parameters will be omitted when the class is ultimately instantiated. (See bellow how constructor arguments are specified on the Stride Runner command line on the host computer.)'' | |||
;C-Class Test Unit | |||
<source lang=c> | <source lang=c> | ||
/*MyTest.h*/ | |||
#include <srtest.h> | #include <srtest.h> | ||
Line 143: | Line 82: | ||
</source> | </source> | ||
<source lang=c> | <source lang=c> | ||
/*MyTest.c*/ | |||
#include "MyTest.h" | #include "MyTest.h" | ||
Line 155: | Line 95: | ||
/* other test implementations */ | /* other test implementations */ | ||
void MyTest_Init(MyTest* self, int nParam, const char* szParam) | void MyTest_Init(MyTest* self, int nParam, const char* szParam) | ||
Line 169: | Line 105: | ||
... | ... | ||
... | ... | ||
}</source> | } | ||
</source> | |||
== | === How to pass via the Runner === | ||
To pass parameter values as constructor arguments you need to specify them between parentheses characters immediately following the Test Unit name on the [[STRIDE Runner | Stride Runner]] command line: | |||
;Number argument | |||
Integer numbers could be specified as either decimal or hexadecimal. C++ <code>true/false</code> could also be specified. | |||
--run=MyTest(17) | |||
--run=MyTest(0x56) | |||
--run=MyTest(21.95) | |||
--run=MyTest(true) | |||
;String argument | |||
String arguments must be enclosed with double quotes. Further, the double quotes should be escaped with a backslash as this is required by the command line processor. | |||
--run="MyOtherTest(\"this is the parameter\")" | |||
--run="FileTest(\"c:\\path\\to\\file\")" | |||
--run="FileTest(\"/path/to/file\")" | |||
;Multiple arguments | |||
--run="YetAnotherTest(19.58, -1, \"Encinitas, CA\", 92024, \"south\")" | |||
'''NOTE:''' ''Be aware that the command line processor (console shell) imposes rules that requires any option's value containing special characters (e.g. space, ", ', |, \, /, *, ?...) to be enclosed within double-quotes. Within these quotes, all double-quote and backslash characters must be escaped with a preceding backslash.'' | |||
* | |||
'''NOTE:''' ''You can specify only some of the argument values, as any omitted will default to empty for C-string or 0 for numeric.'' | |||
== | == Name-Value Collection == | ||
Passing parameters as name-value collection is very powerful, however it requires explicit use of an API to obtain their values and as well a separate file on the host. | |||
=== How to use in your test code === | |||
To use parameters passed as name-value collection you need to call [[Runtime_Test_Services#class_srTest|srTest::GetParam]] for C++ (or [[Runtime_Test_Services#srTestGetParam|srTestGetParam]] for C). | |||
;C++ Test Unit | |||
<source lang=cpp> | |||
//MyTest.h | |||
#include <srtest.h> | #include <srtest.h> | ||
class MyTest : public stride::srTest | class MyTest: public stride::srTest | ||
{ | { | ||
public: | public; | ||
MyTest() | |||
: m_lParam(0) | |||
, m_dParam(0.0) | |||
{ | |||
m_lParam = GetParam("name1", -1); | |||
m_dParam = GetParam("section.name1", 0.5772156649); | |||
GetParam("name2", m_szParam, MAX_VALUE_LEN, "default value"); | |||
} | |||
// | // Tests | ||
void Test1(); | |||
... | |||
... | |||
... | |||
private: | |||
// typically, you will store parameter values into member variables for use by | |||
// the member test methods | |||
long m_lParam; | |||
double m_dParam; | |||
char m_szParam[MAX_VALUE_LEN]; | |||
}; | |||
#ifdef _SCL | |||
#pragma scl_test_class(MyTest) | |||
#endif | |||
</source> | </source> | ||
;C-Class Test Unit | |||
<source lang=c> | |||
/*MyTest.h*/ | |||
#include <srtest.h> | #include <srtest.h> | ||
typdef struct MyTest | |||
{ | |||
long m_lParam; | |||
char m_szParam[MAX_VALUE_LEN]; | |||
void (*Test1)(struct MyTest* self); | |||
... | |||
... | |||
... | ... | ||
}; | } MyTest; | ||
void MyTest_Init(MyTest* self); | |||
<source | #ifdef _SCL | ||
#pragma scl_test_cclass(MyTest, MyTest_Init) | |||
#endif | |||
</source> | |||
# | <source lang=c> | ||
/*MyTest.c*/ | |||
#include "MyTest.h" | |||
static void Test1(MyTest* self) | |||
{ | { | ||
... | ... | ||
... | |||
... | |||
} | |||
/* other test implementations */ | |||
void MyTest_Init(MyTest* self) | |||
{ | |||
self->m_lParam = srTestGetParamLong("name1", -1); | |||
srTestGetParam("section.name2", self->m_szParam, MAX_VALUE_LEN, "default value"); | |||
/ | self->Test1 = Test1; | ||
... | |||
... | |||
... | |||
} | |||
</source> | |||
=== How to pass via the Runner === | |||
To pass parameter values as name-value collection you need to create an [http://en.wikipedia.org/wiki/INI_file INI-formatted file] and specify it ('''without double quite''' encloser) between parentheses characters immediately following the Test Unit name on the [[STRIDE Runner | Stride Runner]] command line: | |||
--run="MyTest(/path/to/file.ini)" | |||
where "/path/to/file.ini" for example could be something like: | |||
<source lang=ini> | |||
# line stating with a hash character are omitted | |||
# global values | |||
name1 = 17 | |||
name2 = this is a parameter | |||
complex.name1 = something else | |||
# section grouped valies | |||
[section] | |||
name1 = 13.86 | |||
name2 = yet another one | |||
</source> | |||
'''NOTE:''' ''The content of the INI-formatted file will be converted to a flat name-value collection, as any name "X" in section "Y" the file will appear under "Y.X" name in the collection. In case a name is repeated, only its last value will be present.'' | |||
'''NOTE:''' ''String values are not required to be double quote enclosed.'' |
Latest revision as of 15:36, 6 July 2015
Stride provides an easy way for passing parameters from the Stride Runner on the host to the test code executing on the target device.
Pass parameters via the command line to your constructor
stride .. --run=MyTest(42)
Pass parameters using a name-value collection
stride .. --run="MyOtherTest(/path/to/file.ini)"
This allows customization of the test behavior at runtime and is useful when you want to run the same test scenario with different sets of input data, as described by this pattern.
There are two ways you could pass parameters:
- as constructor arguments
- as a name-value collection
Constructor Arguments
Passing parameters as constructor arguments is very simple and natural, however could be quite challenging when you need to pass more than a couple.
How to use in your test code
To use parameters passed as constructor arguments you need to implement a public constructor in your C++ Test Unit (or extend the Initialization function of your C-Class Test Unit) with an argument list of C-string and numeric (integer or double) types:
- C++ Test Unit
//MyTest.h
#include <srtest.h>
class MyTest
{
public;
MyTest(int nParam, const char* szParam, double dParam)
: m_nParam(nParam)
, m_dParam(dParam)
{
strncpy(m_szParam, szParam, MAX_VALUE_LEN);
}
// Tests
void Test1();
...
...
...
private:
// typically, you will store parameter values into member variables for use by the member test methods
int m_nParam;
char m_szParam[MAX_VALUE_LEN];
double m_dParam;
};
#ifdef _SCL
#pragma scl_test_class(MyTest)
#endif
NOTE: Don't declare more than one public constructor. This is typically not a problem for non-parameterized test classes, as a common default constructor is what's needed. Often you will begin with a non-parameterized test class and add the parameterization later as your testing gets more sophisticated. A common mistake here is to add a second public parameterized constructor to the class in addition to the original default constructor; this is perfectly legal in C++, but will not give you the desired result.
NOTE: Don't set default values for your constructor arguments. In the case of Stride, each test class is instantiated dynamically on demand by the harnessing code. The harnessing code does not know at build time whether constructor parameters will be omitted when the class is ultimately instantiated. (See bellow how constructor arguments are specified on the Stride Runner command line on the host computer.)
- C-Class Test Unit
/*MyTest.h*/
#include <srtest.h>
typdef struct MyTest
{
int m_nParam;
char m_szParam[MAX_LEN];
void (*Test1)(struct MyTest* self);
...
...
...
} MyTest;
void MyTest_Init(MyTest* self, int nParam, const char* szParam);
#ifdef _SCL
#pragma scl_test_cclass(MyTest, MyTest_Init)
#endif
/*MyTest.c*/
#include "MyTest.h"
static void Test1(MyTest* self)
{
...
...
...
}
/* other test implementations */
void MyTest_Init(MyTest* self, int nParam, const char* szParam)
{
self->m_nParam = nParam;
strncpy(self->m_szParam, szParam, MAX_LEN);
self->Test1 = Test1;
...
...
...
}
How to pass via the Runner
To pass parameter values as constructor arguments you need to specify them between parentheses characters immediately following the Test Unit name on the Stride Runner command line:
- Number argument
Integer numbers could be specified as either decimal or hexadecimal. C++ true/false
could also be specified.
--run=MyTest(17) --run=MyTest(0x56) --run=MyTest(21.95) --run=MyTest(true)
- String argument
String arguments must be enclosed with double quotes. Further, the double quotes should be escaped with a backslash as this is required by the command line processor.
--run="MyOtherTest(\"this is the parameter\")" --run="FileTest(\"c:\\path\\to\\file\")" --run="FileTest(\"/path/to/file\")"
- Multiple arguments
--run="YetAnotherTest(19.58, -1, \"Encinitas, CA\", 92024, \"south\")"
NOTE: Be aware that the command line processor (console shell) imposes rules that requires any option's value containing special characters (e.g. space, ", ', |, \, /, *, ?...) to be enclosed within double-quotes. Within these quotes, all double-quote and backslash characters must be escaped with a preceding backslash.
NOTE: You can specify only some of the argument values, as any omitted will default to empty for C-string or 0 for numeric.
Name-Value Collection
Passing parameters as name-value collection is very powerful, however it requires explicit use of an API to obtain their values and as well a separate file on the host.
How to use in your test code
To use parameters passed as name-value collection you need to call srTest::GetParam for C++ (or srTestGetParam for C).
- C++ Test Unit
//MyTest.h
#include <srtest.h>
class MyTest: public stride::srTest
{
public;
MyTest()
: m_lParam(0)
, m_dParam(0.0)
{
m_lParam = GetParam("name1", -1);
m_dParam = GetParam("section.name1", 0.5772156649);
GetParam("name2", m_szParam, MAX_VALUE_LEN, "default value");
}
// Tests
void Test1();
...
...
...
private:
// typically, you will store parameter values into member variables for use by
// the member test methods
long m_lParam;
double m_dParam;
char m_szParam[MAX_VALUE_LEN];
};
#ifdef _SCL
#pragma scl_test_class(MyTest)
#endif
- C-Class Test Unit
/*MyTest.h*/
#include <srtest.h>
typdef struct MyTest
{
long m_lParam;
char m_szParam[MAX_VALUE_LEN];
void (*Test1)(struct MyTest* self);
...
...
...
} MyTest;
void MyTest_Init(MyTest* self);
#ifdef _SCL
#pragma scl_test_cclass(MyTest, MyTest_Init)
#endif
/*MyTest.c*/
#include "MyTest.h"
static void Test1(MyTest* self)
{
...
...
...
}
/* other test implementations */
void MyTest_Init(MyTest* self)
{
self->m_lParam = srTestGetParamLong("name1", -1);
srTestGetParam("section.name2", self->m_szParam, MAX_VALUE_LEN, "default value");
self->Test1 = Test1;
...
...
...
}
How to pass via the Runner
To pass parameter values as name-value collection you need to create an INI-formatted file and specify it (without double quite encloser) between parentheses characters immediately following the Test Unit name on the Stride Runner command line:
--run="MyTest(/path/to/file.ini)"
where "/path/to/file.ini" for example could be something like:
# line stating with a hash character are omitted
# global values
name1 = 17
name2 = this is a parameter
complex.name1 = something else
# section grouped valies
[section]
name1 = 13.86
name2 = yet another one
NOTE: The content of the INI-formatted file will be converted to a flat name-value collection, as any name "X" in section "Y" the file will appear under "Y.X" name in the collection. In case a name is repeated, only its last value will be present.
NOTE: String values are not required to be double quote enclosed.