期望来自另一个线程的googlemock调用 [英] Expecting googlemock calls from another thread

查看:195
本文介绍了期望来自另一个线程的googlemock调用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

什么是使用google mock对象编写(google)测试用例的最好方法,并期望EXPECT_CALL()定义从测试中的类控制的另一个线程调用?
只是在触发调用序列之后调用sleep()或类似方法并不合适,因为它可能会减慢测试的速度,而不会影响时序条件。但是完成测试用例需要等待模拟方法被调用。
想法任何人?

What will be the best way to write (google) test cases using a google mock object and expect the EXPECT_CALL() definitions being called from another thread controlled by the class in test? Simply calling sleep() or alike after triggering the call sequences doesn't feel appropriate since it may slow down testing unnecessary and may not really hit the timing conditions. But finishing the test case somehow has to wait until the mock methods have been called. Ideas anyone?

下面是一些代码来说明情况:

Here's some code to illustrate the situation:

Bar.hpp class under test)

Bar.hpp (the class under test)

class Bar
{
public:

Bar(IFooInterface* argFooInterface);
virtual ~Bar();

void triggerDoSomething();
void start();
void stop();

private:
void* barThreadMethod(void* userArgs);
void endThread();
void doSomething();

ClassMethodThread<Bar> thread; // A simple class method thread implementation using boost::thread
IFooInterface* fooInterface;
boost::interprocess::interprocess_semaphore semActionTrigger;
boost::interprocess::interprocess_semaphore semEndThread;
bool stopped;
bool endThreadRequested;
};

Bar.cpp(摘录):

Bar.cpp (excerpt):

void Bar::triggerDoSomething()
{
    semActionTrigger.post();
}

void* Bar::barThreadMethod(void* userArgs)
{
    (void)userArgs;
    stopped = false;
    do
    {
        semActionTrigger.wait();
        if(!endThreadRequested && !semActionTrigger.try_wait())
        {
            doSomething();
        }
    } while(!endThreadRequested && !semEndThread.try_wait());
    stopped = true;
    return NULL;
}

void Bar::doSomething()
{
    if(fooInterface)
    {
        fooInterface->func1();
        if(fooInterface->func2() > 0)
        {
            return;
        }
        fooInterface->func3(5);
    }
}

测试代码(摘录,定义中没有什么特别的FooInterfaceMock):

The testing code (excerpt, nothing special in the definition of FooInterfaceMock so far):

class BarTest : public ::testing::Test
{
public:

    BarTest()
    : fooInterfaceMock()
    , bar(&fooInterfaceMock)
    {
    }

protected:
    FooInterfaceMock fooInterfaceMock;
    Bar bar;
};

TEST_F(BarTest, DoSomethingWhenFunc2Gt0)
{
    EXPECT_CALL(fooInterfaceMock,func1())
        .Times(1);
    EXPECT_CALL(fooInterfaceMock,func2())
        .Times(1)
        .WillOnce(Return(1));

    bar.start();
    bar.triggerDoSomething();
    //sleep(1);
    bar.stop();
}

没有sleep()的测试结果:

Test results without sleep():

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BarTest
[ RUN      ] BarTest.DoSomethingWhenFunc2Gt0
../test/BarTest.cpp:39: Failure
Actual function call count doesn't match EXPECT_CALL(fooInterfaceMock, func2())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
../test/BarTest.cpp:37: Failure
Actual function call count doesn't match EXPECT_CALL(fooInterfaceMock, func1())...
         Expected: to be called once
           Actual: never called - unsatisfied and active
[  FAILED  ] BarTest.DoSomethingWhenFunc2Gt0 (1 ms)
[----------] 1 test from BarTest (1 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] BarTest.DoSomethingWhenFunc2Gt0

 1 FAILED TEST
terminate called after throwing an instance of         'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::lock_error> >'
Aborted

启用sleep()的测试结果:

Test results with sleep() enabled:

[==========] Running 1 test from 1 test case.
[----------] Global test environment set-up.
[----------] 1 test from BarTest
[ RUN      ] BarTest.DoSomethingWhenFunc2Gt0
[       OK ] BarTest.DoSomethingWhenFunc2Gt0 (1000 ms)
[----------] 1 test from BarTest (1000 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test case ran. (1000 ms total)
[  PASSED  ] 1 test.

我想避免sleep(),在最好的情况下,不需要改变Bar类。

I want to avoid the sleep(), in best case without need to change the Bar class at all.

推荐答案

Fraser的回答启发了一个使用GMock专用Action的简单解决方案。 GMock使得很容易快速地编写这样的动作。

Fraser's answer inspired me for a simple solution using a GMock specialized Action. GMock makes it very easy to quickly write such Actions.

以下是代码(摘录自BarTest.cpp):

Here's the code (excerpt from BarTest.cpp):

// Specialize an action that synchronizes with the calling thread
ACTION_P2(ReturnFromAsyncCall,RetVal,SemDone)
{
    SemDone->post();
    return RetVal;
}

TEST_F(BarTest, DoSomethingWhenFunc2Gt0)
{
    boost::interprocess::interprocess_semaphore semDone(0);
    EXPECT_CALL(fooInterfaceMock,func1())
        .Times(1);
    EXPECT_CALL(fooInterfaceMock,func2())
        .Times(1)
        // Note that the return type doesn't need to be explicitly specialized
        .WillOnce(ReturnFromAsyncCall(1,&semDone));

    bar.start();
    bar.triggerDoSomething();
    boost::posix_time::ptime until = boost::posix_time::second_clock::local_time() +
            boost::posix_time::seconds(1);
    EXPECT_TRUE(semDone.timed_wait(until));
    bar.stop();
}

TEST_F(BarTest, DoSomethingWhenFunc2Eq0)
{
    boost::interprocess::interprocess_semaphore semDone(0);
    EXPECT_CALL(fooInterfaceMock,func1())
        .Times(1);
    EXPECT_CALL(fooInterfaceMock,func2())
        .Times(1)
        .WillOnce(Return(0));
    EXPECT_CALL(fooInterfaceMock,func3(Eq(5)))
        .Times(1)
        // Note that the return type doesn't need to be explicitly specialized
        .WillOnce(ReturnFromAsyncCall(true,&semDone));

    bar.start();
    bar.triggerDoSomething();
    boost::posix_time::ptime until = boost::posix_time::second_clock::local_time() +
            boost::posix_time::seconds(1);
    EXPECT_TRUE(semDone.timed_wait(until));
    bar.stop();
}

请注意,相同的原则适用于任何其他类型的信号量实现, code> boost :: interprocess :: interprocess_semaphore 。我使用它来测试我们的生产代码,使用它自己的操作系统抽象层和信号量实现。

Note the same principle will work well for any other kind of semaphore implementation as boost::interprocess::interprocess_semaphore. I'm using it for testing with our production code that uses it's own OS abstraction layer and semaphore implementation.

这篇关于期望来自另一个线程的googlemock调用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆