简体   繁体   中英

customizing unittest++

I'm asking this with hopes that somebody has been in my shoes and has some ideas. Trying to avoid reinventing the wheel, so to speak.

I'm using UnitTest++: http://unittest-cpp.sourceforge.net/UnitTest++.html

I've got quite a few tests written by now, and they all execute every time I run the test build, which of course is to be expected. I even defined my own TestReporter class which provides me with a bit more information about each test than the default -- it prints the time it took for each test at the end of it, and also has color-coded test begin and test end messages so it's easier for me to navigate the test output.

But I'm getting to a point where the sheer number of tests dumps out so much output that my console's buffer doesn't even hold the results from the first few tests anymore, and I'm tired of changing that setting. So I'd like to be able to specify as an optional arguments to running the test build the tests I'd like to run and skip the others.

The code for UnitTest++ is fairly straightforward and I admit i could probably figure it out if I stared at it some more but surely somebody out there's already figured this out? I'm trying to come up with a way to connect my argv[] with Test::GetTestList(). I'd like to filter the test list with cmdline arguments and run those tests only.

Hmm. Looks like it's just a linked list. I guess I can just go mutilate it... O(m*n) search, m=total tests, n=specified tests. Well. I keep answering my own questions. Mods: I will post an answer with my solution's implementation. Hopefully it'll save somebody twenty minutes.

Edit: It looks like I really really should use the Predicate thingy:

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();
}   

That way I can just directly use RunTestsIf() .

edit: I think i figured it out. Wow, first foray into template programming.

Here's my solution:

namespace UnitTest {
    class ListFilter {
        char **list;
        int n;
    public:
        ListFilter(char **list_, int count) {
            list = list_; n = count;
        }
        bool operator()(const Test* const t) const {
            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())) {
                    // erring on the side of matching more tests
                    return true;
                }
            }
            return false;
        }
    };

    int RunTheseTests(char ** list, int n) {
        TestReporterStdout reporter;
        TestRunner runner(reporter);
        return runner.RunTestsIf(Test::GetTestList(), NULL, ListFilter(list,n), 0);
    }
}

int main(int argc, char *argv[]) {
    if (argc == 1) {
        UnitTest::RunAllTests();
    } else {
        UnitTest::RunTheseTests(argv+1, argc-1); // skip the program's name itself.
    }
}

Only thing slightly bothers me with this is there's no clean way to check if any given test matchers didn't end up matching anything.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM