单元测试++问题:尝试使用具有状态的谓词

发布于 2024-12-05 03:30:18 字数 3579 浏览 1 评论 0原文

相关代码,来自 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;
};

这是我的谓词类,我试图修改它以使其执行我想要的操作:

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

您可以看到它在 TestRunner 中定义的方式。 h 附加了一个 const 限定符,这使得我的 operator () 函数无法更改成员变量。我需要进行这些更改,以便我可以记住我已经运行了哪些测试,这样我就不会再次运行它们。它们可能存在再次运行风险的原因是我打算多次运行 RunTestsIf()

我在命令行输入测试列表,以根据测试名称指定要运行的测试。这就是所有字符串匹配代码的用途。我仍然想使用它们,但这次我想改进它,以便我指定的测试将按照我指定的顺序运行。为了做到这一点,我必须移动测试运行程序,以便我循环我的测试指定测试列表并根据它们一一进行匹配。

有想法吗?我会破坏 UnitTest++ 代码中的 const,但如果不需要的话我不想破坏东西。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

痕至 2024-12-12 03:30:18

您可以使用 mutable 关键字,但测试的结构方式表明测试运行程序可能不会重用相同的谓词实例,因此您的更改可能会在测试之间丢失。当然,如果发布的代码是整个测试运行程序,那么看起来它每次都会调用相同的 Predicate 实例。

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.

我不吻晚风 2024-12-12 03:30:18

通常您会期望单元测试有一组确定性的东西要测试。这可能更接近集成测试。这并不一定是坏事,只要确保先测试较小的部分即可。

话虽这么说,UnitTest++ 被设计得很小且易于修改。我会扩展或包装它以满足您的需求,但不会破坏现有功能。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文