使用google mock对象编写(google)测试用例的最佳方法是什么,并期待EXPECT_CALL()定义从被测试中的类控制的另一个线程调用?
触发呼叫序列后简单地调用sleep()或类似的操作并不合适,因为它可能会减慢测试速度,并且可能不会真正达到定时条件.但是,完成测试用例必须等到模拟方法被调用.
想法吗?
触发呼叫序列后简单地调用sleep()或类似的操作并不合适,因为它可能会减慢测试速度,并且可能不会真正达到定时条件.但是,完成测试用例必须等到模拟方法被调用.
想法吗?
以下是一些代码来说明情况:
Bar.hpp(被测课)
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(摘录):
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的定义中没有什么特别的):
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(); }
测试结果没有睡眠():
[==========] 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()启用测试结果:
[==========] 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类.
解决方法
Fraser的答案激发了我使用GMock专门的Action的简单解决方案. GMock可以很容易地快速编写这样的动作.
这是代码(摘自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,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::universal_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,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::universal_time() + boost::posix_time::seconds(1); EXPECT_TRUE(semDone.timed_wait(until)); bar.stop(); }
请注意,相同的原则对于任何其他类型的信号量实现都将适用于boost :: interprocess :: interprocess_semaphore.我使用它来测试我们的生产代码,它使用它自己的操作系统抽象层和信号量实现.