无法在 xUnit 中捕获 InvalidOperationException
Unable to catch InvalidOperationException in xUnit
过去一个小时我一直在尝试通过以下测试,但我似乎无法让它工作:
[Fact]
public async void TestDetachedRecordsArentUpdatedWithoutIDs()
{
var options = new DbContextOptionsBuilder<ClientContext>()
.UseInMemoryDatabase(databaseName: "cant_update_detached_clients_with_bankinfos")
.Options;
int clientID, bankInfoID;
using(var context = new ClientContext(options))
{
var service = new ClientService(context);
var bankInfo = new BankInfo { RoutingNumber = "12345" };
var client = new Client { FirstName = "Javier", LastName = "Garcia", BankInfo = bankInfo };
await service.Save(client);
clientID = client.ID;
bankInfoID = client.BankInfo.ID;
}
using(var context = new ClientContext(options))
{
var service = new ClientService(context);
var bankInfo = new BankInfo { RoutingNumber = "Modified" };
var client = new Client { ID = clientID, FirstName = "Modified", BankInfo = bankInfo };
try
{
await service.Save(client);
}
catch (System.InvalidOperationException ex)
{
var expected = "The property 'ID' on entity type 'BankInfo' is part of a key and so cannot be modified or marked as modified.";
Assert.Contains(expected, ex.Message);
}
}
}
我发现的问题是我似乎无法捕捉到异常。这是我每次测试的结果运行吧:
为了提供一点额外的上下文,当调用 ClientService::Save
时,它会调用一个名为 HandleDisconnectedEntities
的方法,当下面的行 运行s:
94: _context.Entry(existingClient.BankInfo).CurrentValues.SetValues(client.BankInfo);
我确实了解异常的性质,但我不明白为什么我的测试无法捕获它。非常感谢任何见解!
这个问题是因为测试定义的 async void
。
public async void TestDetachedRecordsArentUpdatedWithoutIDs() { ...
Async void methods have different error-handling semantics. When an exception is thrown out of an async Task
or async Task<T>
method, that exception is captured and placed on the Task object. With async void
methods, there is no Task
object, so any exceptions thrown out of an async void
method will be raised directly on the SynchronizationContext
that was active when the async void
method started.
Exceptions from an Async Void Method Can’t Be Caught with Catch
例如
private async void ThrowExceptionAsync()
{
throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
try
{
ThrowExceptionAsync();
}
catch (Exception)
{
// The exception is never caught here!
throw;
}
}
将测试改为使用 Task
public async Task TestDetachedRecordsArentUpdatedWithoutIDs() {
//...
}
过去一个小时我一直在尝试通过以下测试,但我似乎无法让它工作:
[Fact]
public async void TestDetachedRecordsArentUpdatedWithoutIDs()
{
var options = new DbContextOptionsBuilder<ClientContext>()
.UseInMemoryDatabase(databaseName: "cant_update_detached_clients_with_bankinfos")
.Options;
int clientID, bankInfoID;
using(var context = new ClientContext(options))
{
var service = new ClientService(context);
var bankInfo = new BankInfo { RoutingNumber = "12345" };
var client = new Client { FirstName = "Javier", LastName = "Garcia", BankInfo = bankInfo };
await service.Save(client);
clientID = client.ID;
bankInfoID = client.BankInfo.ID;
}
using(var context = new ClientContext(options))
{
var service = new ClientService(context);
var bankInfo = new BankInfo { RoutingNumber = "Modified" };
var client = new Client { ID = clientID, FirstName = "Modified", BankInfo = bankInfo };
try
{
await service.Save(client);
}
catch (System.InvalidOperationException ex)
{
var expected = "The property 'ID' on entity type 'BankInfo' is part of a key and so cannot be modified or marked as modified.";
Assert.Contains(expected, ex.Message);
}
}
}
我发现的问题是我似乎无法捕捉到异常。这是我每次测试的结果运行吧:
为了提供一点额外的上下文,当调用 ClientService::Save
时,它会调用一个名为 HandleDisconnectedEntities
的方法,当下面的行 运行s:
94: _context.Entry(existingClient.BankInfo).CurrentValues.SetValues(client.BankInfo);
我确实了解异常的性质,但我不明白为什么我的测试无法捕获它。非常感谢任何见解!
这个问题是因为测试定义的 async void
。
public async void TestDetachedRecordsArentUpdatedWithoutIDs() { ...
Async void methods have different error-handling semantics. When an exception is thrown out of an
async Task
orasync Task<T>
method, that exception is captured and placed on the Task object. Withasync void
methods, there is noTask
object, so any exceptions thrown out of anasync void
method will be raised directly on theSynchronizationContext
that was active when theasync void
method started.Exceptions from an Async Void Method Can’t Be Caught with Catch
例如
private async void ThrowExceptionAsync()
{
throw new InvalidOperationException();
}
public void AsyncVoidExceptions_CannotBeCaughtByCatch()
{
try
{
ThrowExceptionAsync();
}
catch (Exception)
{
// The exception is never caught here!
throw;
}
}
将测试改为使用 Task
public async Task TestDetachedRecordsArentUpdatedWithoutIDs() {
//...
}