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 (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 (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);
}
}
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();
}
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
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.
I want to avoid the sleep(), in best case without need to change the Bar class at all.
timed_wait()
will not work properly if you uselocal_time()
when calculatinguntil
. You should useuniversal_time()
instead. – Philhellene