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
I have had similar problems as you did. The approach I usually take is manage this via a script in order to automate the addition of code to the different places. A comment marks the point for the script to process the file so you don't need to write a complicated parser. Something like:
/* automatic code insertion point. Don't remove this comment */
Then you write a small script. There are many things macros can't do, and obscuring the code in order to write less is seldom a good idea. So write your script that updates the five locations.
精彩评论