我正在尝试使用任务并行库实现激活并忘记功能。通过对Task.Factory.StartNew
的内联调用,一切都按预期工作。但是,我想将Task.Factory.StartNew
调用移动到一个单独的类中,以便我可以添加日志记录,错误处理等,并可能在将来升级代码,因为更好的线程类等添加到.NET Framework中,没有重复的代码。
以下是我希望通过的单元测试,但事实并非如此。我很感激帮助试图弄清楚如何使这项工作。
[TestFixture]
public class ThreadingServiceFixture
{
public static bool methodFired = false;
[Test]
public void CanFireAndForgetWithThreadingService()
{
try
{
var service = new ThreadingService();
service.FireAndForget(() => methodFired = true);
var endTime = DateTime.Now.AddSeconds(1);
while(DateTime.Now < endTime)
{
//wait
}
Assert.IsTrue(methodFired == true);
}
finally
{
methodFired = false;
}
}
}
public class ThreadingService
{
public Task FireAndForget(Action action)
{
return Task.Factory.StartNew(() => action);
}
}
答案 0 :(得分:3)
你没有执行动作,你只是回来了。
尝试:
return Task.Factory.StartNew(() => action());
答案 1 :(得分:2)
您未在ThreadingService
代码应该是类似
的内容public class ThreadingService
{
public Task FireAndForget(Action action)
{
return Task.Factory.StartNew(() => action.Invoke());
}
}
附加说明:使用公共字段测试状态是邪恶的。考虑可重复性,维护,以不同顺序运行测试。您应该在测试中移动bool methodFired
。我还假设有一种更好的技术来测试它(但我不确定是哪一种)。
答案 2 :(得分:2)
如果是&#34;火灾和忘记&#34;您不需要从Task
方法返回FireAndForget
,因为来电者可以获取Task
并取消它(严格来说,来电者会#34;记住&#34 34;电话)。
如果要从许多不从公共ThreadingService
继承的服务调用此方法,可以通过接口实现扩展方法。
public interface IFireAndForget
{
// no member needed.
}
public static class FireAndForgetExtensions
{
public static void FireAndForget(this IFireAndForget obj, Action action)
{
// pass the action, not a new lambda
Task.Factory.StartNew(action);
}
}
// using
public class ThreadingService : IFireAndForget
{
}
另请注意,在您的方法中,您必须将action
传递给传递lambda并返回StartNew
参数的action
方法。
答案 3 :(得分:1)
测试线程代码很难。 根据时间进行测试是一个坏主意,它们可能变得不确定,您可能会在构建服务器上观察到不稳定的行为。想象一下有时会通过的测试,有时却没有!
您的代码有错误,因为您实际上并未调用该操作。
但请考虑这种变化:
[Test]
[TimeOut(5000)]
public void CanFireAndForgetWithThreadingService()
{
var service = new ThreadingService();
ManualResetEvent mre = new ManualRestEvent(bool); // I never remember what is the default...
service.FireAndForget(() => mre.Set() /*will release the test asynchroneously*/);
mre.WaitOne(); // blocks, will timeout if FireAndForget does not fire the action.
}
是的,我们仍在使用计时。但是测试只有在代码中断时才会发生超时! 在所有其他情况下,测试是绝对可预测的,并且执行时间非常短,无需等待和祈祷时间问题不会发生; - )