I have class which has a execute() function. Execution of execute() function only stops when terminate() function is called. I want to test the execute() function.
class Process{
public:
void execute(){ // start execution until terminate() is called.. }
void terminate(){ //stop the processing of execute()... }
}
My unit test case is given below. I am using 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);
}
If using thread a good practice should I close the thread inside the test case instead of detaching it from main thread?
Also better suggestion is appreciable.
First of all access to isRunning
should be synchronized. In your example you can simply use std::atomic<bool>
and be done with it.
Disclaimer: it's been a while since I've done any kind of serios multithreading so take this with a grain of salt. Also, I haven't tested to code, other than to check it compiles.
This is where I would start:
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();
}
This way you check both for execute
to block and for terminate
to terminate and you have more flexibility. If the execute
unblocks early you don't wait your full timeout and for terminate
you have a wiggle to wait for the other thread to finish and you unblock as soon as it does.
If terminate() fails to stop the execution, will th thread continue his execution after the end of this test case?
If terminate
doesn't stop the execution then the 2nd wait_for
ends after timeout returning false
and the assert kicks in. I don't know what testing framework you use and what the Assert
does.
if it returns the execution to test
then the test will block on join
until the thread finishes
if it throws an exception then the join
is not called and at the destructor of th
if the thread has still not ended std::terminate
will be called. This can be changed with a try catch
if it forces an exit (e.g. calls std::terminate
) then... well... your program ends regardless
This is indeed a problem you need to analyze. It all depends on what you want to do if terminate
fails to stop execute
within your wait interval.
if you are ok with waiting within test
, then all you need to do is make sure join
is called. As I've said this is solvable with a try catch
.
if you want to end the current test but are ok with the thread still going on then you need to detach the thread if terminate
failed to end it.
if you want to kill the thread then... that's not possible. You could instead kill the entire app via std::terminate
.