UnitTest++ issues: Trying to use a Predicate that has state
Relevant code, this is from UnitTest++/TestRunner.h
:
class TestRunner
{
public:
explicit TestRunner(TestReporter& reporter);
~TestRunner();
template <class Predicate>
int RunTestsIf(TestList const& list, char const* suiteName,
const Predicate& predicate, int maxTestTimeInMs) const
{
Test* curTest = list.GetHead();
while (curTest != 0)
{
if (IsTestInSuite(curTest,suiteName) && predicate(curTest))
{
RunTest(m_result, curTest, maxTestTimeInMs);
}
curTest = curTest->next;
}
return Finish();
}
private:
TestReporter* m_reporter;
TestResults* m_result;
Timer* m_timer;
int Finish() const;
bool IsTestInSuite(const Test* const curTest, char const* suiteName) const;
void RunTest(TestResults* const result, Test* const curTest, int const maxTestTimeInMs) const;
};
Here is my predicate class I am trying to modify to let it do what I want:
class ListFilterRemember {
char **list;
int n;
Test **testsAlreadyRun;
int index_tar;
int max_allocd;
public:
ListFilterRemember(char **list_, int count) {
int testCount = 0;
Test* curTest = Test::GetTestList().GetHead();
while (curTest != 0) {
testCount++;
}
list = list_; n = count; max_allocd = testCount;
testsAlreadyRun = new Test *[max_allocd];
index_tar = 0;
}
bool operator()(const Test* const t) const {
for (int i=0;i<index_tar;++i) {
if (testsAlreadyRun[i] == t) { return false; }
}
for (int i=0;i<n;++i) {
std::string dot_cpp_appended = std::string(list[i]) + ".cpp";
if (!strcasecmp(t->m_details.testName, list[i]) ||
!strcasecmp(t->m_details.suiteName, list[i]) ||
!strcasecmp(t->m_details.filename, list[i]) ||
!strcasecmp(t->m_details.filename, dot_cpp_appended.c_str()) || (
filename_dir_prefix_len < (int)strlen(t->m_details.filename) && ( // ensure the ptr arith in next 2 lines doesn't go out of bounds
!strcasecmp(t->m_details.filename+filename_dir_prefix_len, list[i]) ||
!strcasecmp(t->m_details.filename+filename_dir_prefix_len, dot_cpp_appended.c_str())
)
) || (
std::string::npos != findCaseInsensitive(t->m_details.testName,list[i])
)
) {
// erring on the side of matching more tests
//printf(" running\n");
if (index_tar >= max_allocd) throw std::runtime_error("Did not allocate! Segfault here.");
testsAlreadyRun[index_tar] = (Test *)t;
index_tar += 1;
开发者_高级运维 return true;
}
}
//printf(" not running\n");
return false;
}
~ListFilterRemember() {
delete[] testsAlreadyRun;
}
};
You see the way that it's defined in TestRunner.h
attaches a const qualifier which makes it impossible for my operator ()
function to make changes to member variables. I need to make those changes so I can remember which tests I've already run so I don't run them again. The reason why there might be risk of them running again is that I intend to run RunTestsIf()
multiple times.
I enter a list of tests at the command line to specify which tests I want to run based on their names. That is what all of the string matching code is for. I still want to use those, but this time I want to improve it so that the tests I specify will run in the order that i specify them in. In order to do this I have to move the test runner so that I loop over my specified test list and match based on them one by one.
Ideas? I'd go nuke the const in the UnitTest++ code but I don't want to break things if I don't have to.
You could use the mutable
keyword, but the way the test is structured suggests that the test runner might not reuse the same instance of the predicate, so your changes might be lost between tests. Of course, if the posted code is the entire test runner, then it looks like it does call the same Predicate
instance every time.
Usually you'd expect a unit test to have a deterministic set of things to test. This might be closer to an integration test. Not that that is bad necessarily, just make sure you test the smaller bits first.
That being said, UnitTest++ was designed to be small and easily modified. I'd extend or wrap it to suit your needs, not break existing functionality though.
精彩评论