我希望能够在单元测试中验证传递给异步方法的参数。但由于该方法是异步的,执行断言的任务对整体的单元测试没有影响。断言的异常不会传递给单元测试框架(xunit)。我正在模拟我的存储库方法,这些方法由MVC IHostedService调用。
示例:
CancellationTokenSource sourceToken = new CancellationTokenSource();
var repositoryMock = new Mock<IRepository>();
repositoryMock.Setup(x => x.BulkUpdate(It.IsAny<IEnumerable<MyDocument>>(), It.IsAny<bool>()))
.ReturnsAsync((IEnumerable<MyDocument> notifications, bool upsert) =>
{
// verify all the event Ids are in the newly created Notifications (these will actually all be NULL since we can't set the eventIds in the Event object
Assert.True(notifications.All(x => x.Detail != null));
Assert.True(notifications.All(x => x.Map != null));
sourceToken.Cancel();
return notifications.Select(x => x.Id);
});
await Assert.ThrowsAsync<TaskCanceledException>(async () => await Task.Delay(20000, sourceToken.Token));
Assert.True(sourceToken.IsCancellationRequested);
此处的示例不包括启动MVC服务,但Startup将我的IHostedService创建为单例,它也会立即启动它。它最终将调用此BulkUpdate方法,并且我希望能够验证IHostedService是否使用正确的数据调用BulkUpdate。 CancellationTokenSource用于表示测试可以退出,因为IHostedService已经完成了我想要测试的工作。
后台服务的启动方式: 在单元测试启动类中:
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton<IHostedService, MyBackgroundService>();
}
我们有一个生成IWebHostBuilder的方法......
internal static IWebHostBuilder GetWebHostBuilder(Mock<IIRepository> repositoryMock = null)
{
var environment = "Development"; //
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{environment}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
var configuration = builder.Build();
var webHostBuilder = new WebHostBuilder()
.UseEnvironment(environment)
.UseConfiguration(configuration)
.ConfigureServices(services =>
{
// Add the repository mocks and the type of user thats needed for authentications in the Controller being tested
// These will be added before the IntegrationTestStartup.ConfigureTransientServices method runs and adds
// the repository objects.
if(repositoryMock != null)
services.AddTransient<IRepository>((y) => { return repositoryMock.Object; });
})
.UseStartup<UnitTestStartup>(); // This is the Startup of AHENS
return webHostBuilder;
}
我们在单元测试中使用注入模拟存储库来测试后台服务......
TestServer testServer = new TestServer(TestBase.GetWebHostBuilder(repositoryMock));
这一切都“有效”,除非其中一个断言失败(抛出异常)。如何让断言汇总到单元测试以使测试失败?有没有更好的方法呢?我们有一些测试用例,我们想验证模拟的存储库方法是不是被调用,还是被多次调用。这是多线程应用程序问题的单元测试。
答案 0 :(得分:0)
如果我理解正确,您试图断言BulkUpdate的参数是您所期望的,可以这样做......
repositoryMock.Verify(x => x.BulkUpdate(It.Is<IEnumerable<MyDocument>>(
notifications=>notifications.All(n => n.Detail != null)), It.IsAny<bool>()));
然后类似于Map
。