Background:
I currently write test cases for the client side of a network protocol. As part of the tests I have to simulate several different expected and unexpected responses from the server (wrong header, connection lost, unexpected messages, timeouts).
Each of these test-cases can be accessed by its unique address.
My problem:
The current implementation is split into several parts:
- An enum containing all the addresses of the test-cases
- A class Tests containing all tests as static functions
- A number of defines which map the function name to the corresponding enum + _FUNC
- A wrapper class which takes an address a function and a name as argument
- A method which returns a list of wrapper-class objects, one object for each test-case
For each message received the server checks the list of test-cases and either executes the test-case corresponding to the address or falls back to a default response.
The Question:
This implementation requires me to update at least five different locations for each new test-case and the class Test grows rather fast. Is there a good way to refactor it?
Example code:(this code is not valid c++)
enum TestAddress
{
TEST_CONNECTION_BREAKDOWN = 0x100,
TEST_ALL_IS_GOOD = 0x101,
}
class Wrapper : AbstrTestCase //AbstrTestCase requires applies and test implementations
{
typedef testFun;
Wrapper(TestAddress addr,testFun func,string name)
boolean applies(int ad,...){return addr == ad;}
int test(...){return func(...);}
}
class Test
{
static int testConnectionBreakDownFunc (...)
static int testAllIsGoodFunc(...)
}
#define TEST_CONNECTION_BREAKDOWN_FUNC Test::testConnectionBreakDownFunc
#define TEST_ALL_IS_GOOD_FUNC Test::testAllIsGoodFunc
list<AbstrTestCase*> GetTests()
{
list<AbstrTestCase*> tlist;
tlist.push_back(new Wrapper(TEST_ALL_IS_GOOD,TEST_ALL_IS_GOOD_FUNC,"TEST_ALL_IS_GOOD"));
...
tlist.push_back(new Wrapper(TEST_CONNECTION_BREAKDOWN,TEST_CONNECTION_BREAKDOWN_FUNC,"TEST_CONNECTION_BREAKDOWN_FUNC"));
return tlist;
}
Related: My last atemp to at least clean up the code in GetTests() was an additional define for the arguments of wrapper
#define WRAP_ARGS(N) N,N##_FUNC,#N
tlist.push_back(new Wrapper(WRAP_ARGS(TEST_CONNECTION_BREAKDOWN));
#undef WRAP_ARGS(N)
while it results in cleaner looking code, it only hides the problem