I have unit test sample code that basically runs 2 threads: the main test thread and another thread I'm launching that is supposed to fail the test execution after some time (this is basically a timeout thread)
Code is as follows:
[TestClass]
public class SomeTestClass
{
[TestInitialize]
public void BeforeTest()
{
var task = new Task(abortIfTestStilRunsAfterTimeout);
task.Start();
}
[TestMethod]
public void TestMethod()
{
Thread.Sleep(5000);
}
private void abortIfTestStilRunsAfterTimeout()
{
Assert.Fail("timeout passed!");
}
}
Well, I was expecting that the TestMethod()
test should fail but what actually happens is that the task thread that runs the Assert.Fail
method gets an exception while the other thread keeps on running and the test passes.
I'm looking for a way to fail the test method
You can try and get a reference to the test thread and call Abort()
on it. You can pass an exception state object to Abort()
which you can use to pass a fail message:
[TestClass]
public class SomeTestClass
{
Thread testThread;
[TestInitialize]
public void BeforeTest()
{
testThread = Thread.CurrentThread;
var task = new Task(abortIfTestStilRunsAfterTimeout);
task.Start();
}
[TestMethod]
public void TestMethod()
{
try
{
Thread.Sleep(5000);
}
catch (ThreadAbortException e)
{
Assert.Fail((string)e.ExceptionState);
}
}
private void abortIfTestStilRunsAfterTimeout()
{
testThread.Abort("timeout passed!");
}
}
In case you do not want to modify some 100 tests you can use a tool like PostSharp to modify your test cases by inserting the try {} catch {}
logic around each test case for you. All it boils down to is to write an attribute and decorate you test assembly with it (it's called Aspect Oriented Programming and the framework in PostSharp for that is called Laos).
The idea is simple - just run main test logic in a task/thread, and just put timeout handling code in the test method/test initialize. Some kind of Inversion of Control:
// Test class level
ManualResetEvent mre = new ManualResetEvent(false);
[TestMethod]
public void TestMethod()
{
// start waiting task
Task task = Task.Factory.StartNew(() =>
{
// Test Body HERE!
// ...
// if test passed - set event explicitly
mre.Set();
});
// Timeout handling logic,
// !!! I believe you can put it once in the TestInitialize, just check
// whether Assert.Fail() fails the test when called from TestInitialize
mre.WaitOne(5000);
// Check whether ManualResetEvent was set explicitly or was timeouted
if (!mre.WaitOne(0))
{
task.Dispose();
Assert.Fail("Timeout");
}
}
PS: Regarding WaitOne(0)
trick, MSDN:
If millisecondsTimeout is zero, the method does not block. It tests the state of the wait handle and returns immediately.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With