从单元测试用例中运行线程是否是一种好习惯?

时间:2018-10-27 03:38:07

标签: c++ unit-testing visual-c++ mstest

我有一个具有execute()函数的类。执行execute() 该函数仅在调用Terminate()函数时停止。我要测试execute()函数。

class Process{
public:

    void execute(){ // start execution until terminate() is called.. }

    void terminate(){ //stop the processing of execute()... }

}

我的单元测试用例如下。我正在使用MSTest。

TEST_METHOD(StartTest)
{
    Process p;
    bool isRunning = true;
    std::thread th([&](){
        p.execute();
        isRunning = false;
    });
    th.detach();
    std::this_thread::sleep_for(std::chrono::milliseconds(300));

    Assert::isTrue(isRunning);
}

如果使用线程是一种好习惯,那么我应该关闭测试用例中的线程,而不是将其与主线程分离吗?

更好的建议是可取的。

1 个答案:

答案 0 :(得分:3)

首先应该同步对isRunning的访问。在您的示例中,您只需使用std::atomic<bool>即可完成操作。

免责声明:自从我完成了任何类型的serios多线程以来,已经有一段时间了,因此请花点时间。另外,除了检查其可编译性之外,我还没有测试过代码。

这就是我要开始的地方:

auto test()
{
    std::condition_variable cv{};
    std::mutex m{};

    Process p{};
    bool isRunning{true};

    std::thread th([&] {
        p.execute();        
        {
            std::lock_guard<std::mutex> lk{m};
            isRunning = false;
        }
        cv.notify_one();
    });

    {
        std::unique_lock<std::mutex> lk{m};
        // expect timeout
        Assert::isFalse(cv.wait_for(lk, std::chrono::milliseconds(300),
                                   [&] () { return !isRunning; }));
    }

    p.terminate();

    {
        std::unique_lock<std::mutex> lk{m};
        // expect condition to change
        Assert::isTrue(cv.wait_for(lk, std::chrono::milliseconds(300),
                                   [&] () { return !isRunning; }));
    }

    th.join();
}

通过这种方式,您既可以检查execute是否被阻止,又可以检查terminate是否终止,则可以更大的灵活性。如果execute提早解除阻止,您就不必等待整个超时,而terminate则有一个摆动要等待另一个线程结束,并尽快解除阻塞。


  

如果terminate()无法停止执行,则该线程将继续   在这个测试用例结束后他的处决?

如果terminate没有停止执行,则第二个wait_for在超时返回false之后结束,并且断言启动。我不知道您使用的测试框架是什么, Assert会这样做。

  • 如果将执行返回到test,则测试将在join上阻塞,直到线程完成

  • 如果引发异常,则不调用join,如果线程尚未结束,则在th的析构函数中调用std::terminate。可以使用try catch

  • 进行更改
  • 如果它强制退出(例如调用std::terminate),那么...好吧...您的程序结束,无论

这确实是您需要分析的问题。如果terminate在您的等待间隔内未能停止execute,这完全取决于您要做什么。

  • 如果可以在test中等待,那么您要做的就是确保调用了join。正如我所说的,try catch可以解决。

  • 如果您想结束当前测试,但是仍然可以继续运行线程,那么如果terminate无法结束线程,则需要分离线程。

  • 如果您想杀死线程,那么...那是不可能的。您可以改为通过std::terminate杀死整个应用。