从 Func<Task<T>> 获取结果
Getting result from Func<Task<T>>
正在测试的方法
protected override async Task<Name> DoExecuteAsync(NameContext context)
{
context.ThrowIfNull("context");
var request = new Request
{
Id = context.Id,
Principal = context.UserPrincipal,
};
return await this.repository.NameAsync(request, new CancellationToken(), context.ControllerContext.CreateLoggingContext());
}
protected override Name HandleError(NameContext viewContext, Exception exception)
{
if (this.errorSignaller != null)
{
this.errorSignaller.SignalFromCurrentContext(exception);
}
return Name.Unknown;
}
这是
的实现
public abstract class BaseQueryAsync<TInput, TOutput> : IQueryAsync<TInput, TOutput>
{
public async Task<TOutput> ExecuteAsync(TInput context)
{
try
{
return await this.DoExecuteAsync(context);
}
catch (Exception e)
{
return this.HandleError(context, e);
}
}
protected abstract Task<TOutput> DoExecuteAsync(TInput context);
protected virtual TOutput HandleError(TInput viewContext, Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
测试用例如下
[SetUp]
public void Setup()
{
var httpContext = MvcMockHelpers.MockHttpContext(isAuthenticated: true);
this.controller = new Mock<Controller>();
this.controller.Object.SetMockControllerContext(httpContext.Object);
this.repoMock = new Mock<IRepository>();
this.errorSignaller = new Mock<IErrorSignaller>();
this.query = new NameQuery(this.repoMock.Object, this.errorSignaller.Object);
this.userPrinciple = new Mock<IPrincipal>();
this.context = new NameContext(this.controller.Object.ControllerContext, this.userPrinciple.Object);
}
[Test]
public async Task TestDoExecuteAsyncWhenRepositoryFails()
{
// Arrange
this.repoMock.Setup(
x => x.NameAsync(
It.IsAny<Request>(),
It.IsAny<CancellationToken>(),
It.IsAny<ILoggingContext>())).Throws<Exception>();
// Act
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
// Assert
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
}
为了验证名称对象,当我在
行前使用 var result = await act()
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
this.errorSignaller.Verify
失败,因为它的计数是 2 而不是 1。我的目的是检查 Name
对象以及下面的代码。
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
我知道如果我写一个新的测试用例我可以很容易地验证它,但是我有什么办法可以在这个测试中一起做吗?
如果你想测试结果然后使用:
名称结果=等待this.query.ExecuteAsync(this.context);
result.Should().Be(expectefResult);
确保你的测试方法public异步任务
您可以尝试用
查看
await query.ExecuteAsync(this.context);
或
this.query.ExecuteAsync(this.context).GetAwaiter().GetResult();
如果是 Func:
act.Invoke().GetAwaiter().GetResult();
更新
为了能够验证名称,您需要在函数中进行设置。
//...code removed for brevity
Name expectedName = Name.Unknown;
Name actualName = null;
// Act
Func<Task> act = async () => {
actualName = await this.query.ExecuteAsync(this.context);
};
// Assert
act.ShouldNotThrow();
actualName
.Should().NotBeNull()
.And.Be(expectedName);
//...rest of code
原创
正如评论中已经提到的,act
是 returns 一个 Task
.
的函数
虽然等待其实现,但仍需要调用函数本身。由于函数 returns 是一个任务,因此也需要等待它。
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
var name = await act();
相当于有下面的功能
async Task<Name> act() {
return await this.query.ExecuteAsync(this.context);
}
您将不得不以同样的方式等待它
var name = await act();
唯一的区别是前一个示例在委托中具有函数。
尽量避免将 .Result
之类的阻塞调用与 async/await 代码混合使用。这往往会导致死锁。
正在测试的方法
protected override async Task<Name> DoExecuteAsync(NameContext context)
{
context.ThrowIfNull("context");
var request = new Request
{
Id = context.Id,
Principal = context.UserPrincipal,
};
return await this.repository.NameAsync(request, new CancellationToken(), context.ControllerContext.CreateLoggingContext());
}
protected override Name HandleError(NameContext viewContext, Exception exception)
{
if (this.errorSignaller != null)
{
this.errorSignaller.SignalFromCurrentContext(exception);
}
return Name.Unknown;
}
这是
的实现public abstract class BaseQueryAsync<TInput, TOutput> : IQueryAsync<TInput, TOutput>
{
public async Task<TOutput> ExecuteAsync(TInput context)
{
try
{
return await this.DoExecuteAsync(context);
}
catch (Exception e)
{
return this.HandleError(context, e);
}
}
protected abstract Task<TOutput> DoExecuteAsync(TInput context);
protected virtual TOutput HandleError(TInput viewContext, Exception exception)
{
ExceptionDispatchInfo.Capture(exception).Throw();
}
}
测试用例如下
[SetUp]
public void Setup()
{
var httpContext = MvcMockHelpers.MockHttpContext(isAuthenticated: true);
this.controller = new Mock<Controller>();
this.controller.Object.SetMockControllerContext(httpContext.Object);
this.repoMock = new Mock<IRepository>();
this.errorSignaller = new Mock<IErrorSignaller>();
this.query = new NameQuery(this.repoMock.Object, this.errorSignaller.Object);
this.userPrinciple = new Mock<IPrincipal>();
this.context = new NameContext(this.controller.Object.ControllerContext, this.userPrinciple.Object);
}
[Test]
public async Task TestDoExecuteAsyncWhenRepositoryFails()
{
// Arrange
this.repoMock.Setup(
x => x.NameAsync(
It.IsAny<Request>(),
It.IsAny<CancellationToken>(),
It.IsAny<ILoggingContext>())).Throws<Exception>();
// Act
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
// Assert
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
}
为了验证名称对象,当我在
行前使用var result = await act()
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
this.errorSignaller.Verify
失败,因为它的计数是 2 而不是 1。我的目的是检查 Name
对象以及下面的代码。
act.ShouldNotThrow();
this.errorSignaller.Verify(s => s.SignalFromCurrentContext(It.IsAny<Exception>()), Times.Once);
我知道如果我写一个新的测试用例我可以很容易地验证它,但是我有什么办法可以在这个测试中一起做吗?
如果你想测试结果然后使用:
名称结果=等待this.query.ExecuteAsync(this.context);
result.Should().Be(expectefResult);
确保你的测试方法public异步任务
您可以尝试用
查看await query.ExecuteAsync(this.context);
或
this.query.ExecuteAsync(this.context).GetAwaiter().GetResult();
如果是 Func:
act.Invoke().GetAwaiter().GetResult();
更新
为了能够验证名称,您需要在函数中进行设置。
//...code removed for brevity
Name expectedName = Name.Unknown;
Name actualName = null;
// Act
Func<Task> act = async () => {
actualName = await this.query.ExecuteAsync(this.context);
};
// Assert
act.ShouldNotThrow();
actualName
.Should().NotBeNull()
.And.Be(expectedName);
//...rest of code
原创
正如评论中已经提到的,act
是 returns 一个 Task
.
虽然等待其实现,但仍需要调用函数本身。由于函数 returns 是一个任务,因此也需要等待它。
Func<Task<Name>> act = async () => await this.query.ExecuteAsync(this.context);
var name = await act();
相当于有下面的功能
async Task<Name> act() {
return await this.query.ExecuteAsync(this.context);
}
您将不得不以同样的方式等待它
var name = await act();
唯一的区别是前一个示例在委托中具有函数。
尽量避免将 .Result
之类的阻塞调用与 async/await 代码混合使用。这往往会导致死锁。