测试任务延迟
Testing task delay
不确定如何实现。我正在尝试对等待几分钟的方法进行单元测试,请参阅此处:
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public JctTest Execute(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
Task.Delay(jctLoggedInTimeOut)
.ContinueWith(x => _queues.Publish(message));
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
这是我的测试方法,但我无法模拟任务延迟。
[Test]
public void TaskTest()
{
// arrange
var imei = _fixture.Create<string>();
_appSettings.Setup(c => c["JctLogInTimeOut"]).Returns("5");
var message = _fixture.Build<JctRestartViaSmsAttempt>()
.With(x => x.Imei, imei)
.Create();
var sut = _fixture.Create<JctRestartViaSmsAttemptTestRunner>();
// act
sut.Execute(message);
// assert
_queues.Verify(x => x.Publish(It.Is<JctRestartViaSmsValidate>(y => y.Imei == imei)));
}
这是引发的错误:
Moq.MockException : Expected invocation on the mock at least once,
but was never performed: x =>
x.Publish(It.Is(y => y.Imei == .imei)) No
setups configured. No invocations performed. at
Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable1
setups, IEnumerable
1 actualCalls, Expression expression, Times times,
Int32 callCount) at Moq.Mock.VerifyCalls(Interceptor
targetInterceptor, MethodCall expected, Expression expression, Times
times) at Moq.Mock.Verify[T](Mock1 mock, Expression
1 expression,
Times times, String failMessage) at Moq.Mock1.Verify(Expression
1
expression) at
JustEat.PrivateAPN.Worker.UnitTests.TestRunners.JctRestartViaSmsAttemptTestFixture.RunJctTest_WhenRestartAttemptSmsIsSent_ShouldPublishJctRestartValidateMessageWithTheRightImei()
in
我知道我需要 customize/configure 我的 fixture 才能进入回调,但我不确定该怎么做,任何帮助将不胜感激
execute 方法不是真正可测试的,因为它启动了一个延迟任务,但您无法从外部管理该任务。
因此,您可以尝试使用 Thread.Sleep
,这不太好但应该可以:
[Test]
public void TaskTest()
{
// arrange
var imei = _fixture.Create<string>();
_appSettings.Setup(c => c["JctLogInTimeOut"]).Returns("1");
var message = _fixture.Build<JctRestartViaSmsAttempt>()
.With(x => x.Imei, imei)
.Create();
var sut = _fixture.Create<JctRestartViaSmsAttemptTestRunner>();
// act
sut.Execute(message);
// verify the task was not executed yet
// ....
// let the test thread sleep and give the task some time to run
Thread.Sleep(2000);
// assert
_queues.Verify(x => x.Publish(It.Is<JctRestartViaSmsValidate>(y => y.Imei == imei)));
}
我认为问题是允许测试完成。您在延迟开始后创建了一个新任务,但测试功能本身在此之前完成。
我对测试框架不是很熟悉。但我希望你想在任务结束时使用 .Wait() 。这将创建一个阻塞任务,您的主测试线程将被阻塞,直到延迟完成。
你不应该在 await
未完成 的情况下关闭 Task
,当 你的测试和其他事情可能取决于结果.
所以我建议你改成:
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public async Task<JctTest> ExecuteAsync(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
// this will now delay in a non blocking fashion.
await Task.Delay(jctLoggedInTimeOut);
_queues.Publish(message);
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
await
ing 的另一个原因是你有这个 _queues
如果你打算稍后从中读取,你永远不能保证内容,因为线程池中可能仍然有一个线程处理 Task.Delay
.
备选
如果您不能更改方法的签名,那么您将不得不使用 Thread.Sleep()
,它将阻塞当前线程,直到它完成。
因为您确实指定了 Task.Delay
我假设您使用它是为了获得非阻塞的好处。
如果您要使用 Thread.Sleep()
,您可能需要考虑 运行在 Task.Run()
中设置 JctRestartViaSmsAttemptTestRunner
,这样只会阻塞它所在的线程 运行继续。
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public JctTest Execute(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
Thread.Wait(jctLoggedInTimeOut.Milliseconds);
_queues.Publish(message);
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
测试
如果您有执行 return Task<>
的方法,那么如果您没有 async
测试方法签名,则必须使用 .Result
。如果您 运行 连续进行所有测试,这应该不是问题。如果您不知道为什么 .Result
和 .Wait()
不好,请阅读 here
所以对于你的异步版本:
JctTest test = runner.ExecuteAsync().Result;
并且您的非异步版本保持不变。
不确定如何实现。我正在尝试对等待几分钟的方法进行单元测试,请参阅此处:
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public JctTest Execute(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
Task.Delay(jctLoggedInTimeOut)
.ContinueWith(x => _queues.Publish(message));
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
这是我的测试方法,但我无法模拟任务延迟。
[Test]
public void TaskTest()
{
// arrange
var imei = _fixture.Create<string>();
_appSettings.Setup(c => c["JctLogInTimeOut"]).Returns("5");
var message = _fixture.Build<JctRestartViaSmsAttempt>()
.With(x => x.Imei, imei)
.Create();
var sut = _fixture.Create<JctRestartViaSmsAttemptTestRunner>();
// act
sut.Execute(message);
// assert
_queues.Verify(x => x.Publish(It.Is<JctRestartViaSmsValidate>(y => y.Imei == imei)));
}
这是引发的错误:
Moq.MockException : Expected invocation on the mock at least once, but was never performed: x => x.Publish(It.Is(y => y.Imei == .imei)) No setups configured. No invocations performed. at Moq.Mock.ThrowVerifyException(MethodCall expected, IEnumerable
1 setups, IEnumerable
1 actualCalls, Expression expression, Times times, Int32 callCount) at Moq.Mock.VerifyCalls(Interceptor targetInterceptor, MethodCall expected, Expression expression, Times times) at Moq.Mock.Verify[T](Mock1 mock, Expression
1 expression, Times times, String failMessage) at Moq.Mock1.Verify(Expression
1 expression) at JustEat.PrivateAPN.Worker.UnitTests.TestRunners.JctRestartViaSmsAttemptTestFixture.RunJctTest_WhenRestartAttemptSmsIsSent_ShouldPublishJctRestartValidateMessageWithTheRightImei() in
我知道我需要 customize/configure 我的 fixture 才能进入回调,但我不确定该怎么做,任何帮助将不胜感激
execute 方法不是真正可测试的,因为它启动了一个延迟任务,但您无法从外部管理该任务。
因此,您可以尝试使用 Thread.Sleep
,这不太好但应该可以:
[Test]
public void TaskTest()
{
// arrange
var imei = _fixture.Create<string>();
_appSettings.Setup(c => c["JctLogInTimeOut"]).Returns("1");
var message = _fixture.Build<JctRestartViaSmsAttempt>()
.With(x => x.Imei, imei)
.Create();
var sut = _fixture.Create<JctRestartViaSmsAttemptTestRunner>();
// act
sut.Execute(message);
// verify the task was not executed yet
// ....
// let the test thread sleep and give the task some time to run
Thread.Sleep(2000);
// assert
_queues.Verify(x => x.Publish(It.Is<JctRestartViaSmsValidate>(y => y.Imei == imei)));
}
我认为问题是允许测试完成。您在延迟开始后创建了一个新任务,但测试功能本身在此之前完成。
我对测试框架不是很熟悉。但我希望你想在任务结束时使用 .Wait() 。这将创建一个阻塞任务,您的主测试线程将被阻塞,直到延迟完成。
你不应该在 await
未完成 的情况下关闭 Task
,当 你的测试和其他事情可能取决于结果.
所以我建议你改成:
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public async Task<JctTest> ExecuteAsync(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
// this will now delay in a non blocking fashion.
await Task.Delay(jctLoggedInTimeOut);
_queues.Publish(message);
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
await
ing 的另一个原因是你有这个 _queues
如果你打算稍后从中读取,你永远不能保证内容,因为线程池中可能仍然有一个线程处理 Task.Delay
.
备选
如果您不能更改方法的签名,那么您将不得不使用 Thread.Sleep()
,它将阻塞当前线程,直到它完成。
因为您确实指定了 Task.Delay
我假设您使用它是为了获得非阻塞的好处。
如果您要使用 Thread.Sleep()
,您可能需要考虑 运行在 Task.Run()
中设置 JctRestartViaSmsAttemptTestRunner
,这样只会阻塞它所在的线程 运行继续。
internal class JctRestartViaSmsAttemptTestRunner : ITestRunner<JctRestartViaSmsAttempt>
{
private readonly IMayWantMonitoring _queues;
private readonly IAppSettings _appSettings;
public JctRestartViaSmsAttemptTestRunner(IMayWantMonitoring queues, IAppSettings appSettings)
{
_queues = queues;
_appSettings = appSettings;
}
public JctTest Execute(JctRestartViaSmsAttempt jctMessageType)
{
// after five minutes, publish an event to check if the JCT logged in
var jctLoggedInTimeOut = TimeSpan.FromMinutes(double.Parse(_appSettings["JctLogInTimeOut"]));
var message = new JctRestartViaSmsValidate(jctMessageType.Imei);
Thread.Wait(jctLoggedInTimeOut.Milliseconds);
_queues.Publish(message);
// reset test values
return new JctTest("6", jctMessageType.Imei, null, null, null);
}
}
测试
如果您有执行 return Task<>
的方法,那么如果您没有 async
测试方法签名,则必须使用 .Result
。如果您 运行 连续进行所有测试,这应该不是问题。如果您不知道为什么 .Result
和 .Wait()
不好,请阅读 here
所以对于你的异步版本:
JctTest test = runner.ExecuteAsync().Result;
并且您的非异步版本保持不变。