¿Cuál será la mejor manera de escribir (google) casos de prueba utilizando un objeto simulado google y esperar que las definiciones EXPECT_CALL() se llamen desde otro hilo controlado por la clase en prueba? Simplemente llamando a sleep() o similar después de activar las secuencias de llamadas no se considera apropiado, ya que puede ralentizar las pruebas innecesarias y puede que no afecten realmente las condiciones de tiempo. Pero terminar el caso de prueba de alguna manera tiene que esperar hasta que se invoquen los métodos simulados. Ideas anyone?Esperando llamadas googlemock de otro hilo
Aquí hay algo de código para ilustrar la situación:
Bar.hpp (la clase bajo prueba)
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 (extracto):
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);
}
}
El código de prueba (extracto, nada especial en la definición de FooInterfaceMock hasta ahora):
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();
}
resultados de las pruebas sin dormir():
[==========] 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
Resultados de las pruebas con el sueño() activados:
[==========] 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.
quiero evitar el sueño(), en el mejor de los casos, sin necesidad de cambiar la barra de clase en absoluto.
El 'timed_wait()' no funcionará correctamente si usa 'local_time()' al calcular 'until'. Deberías usar 'universal_time()' en su lugar. – Rom098
@ Rom098 THX para la pista.El ejemplo real que tengo usa nuestro propio OSAL, puse las funciones de impulso aquí como un sustituto conciso. –