.NET Core中的xUnit集成测试会出现错误"已经添加了具有相同密钥的项目"

时间:2017-03-10 03:41:06

标签: c# .net-core xunit

我正在使用xUnit在.NET Core应用程序中执行集成测试。我正在关注this post的集成测试部分。它向我介绍了一个TestFixture,它在一个内存服务器中托管项目。启动代码使用Assets表中的两个记录初始化内存数据库。测试如下所示。

我遇到的问题是,当我运行这些测试时,它们会因错误而失败:已添加具有相同键的项目

我认为这是因为Startup试图在数据库中为每个测试添加相同的两条记录。如果我第二次运行测试,它们会通过。当我第三次运行它们时,它们会失败,并像这样交替。当我在Starup代码中放入一个初始化数据库的断点时,看起来有两个线程试图执行断点行,因为当我按F10转到下一行时,执行保持在同一行。我怎样才能确认这是问题所在?如果确实如此!

public class AssetControllerTests : IClassFixture<TestFixture<ManagementSystemCore.Startup>>
{
    private readonly HttpClient _client;

    public AssetControllerTests(TestFixture<ManagementSystemCore.Startup> fixture)
    {
        _client = fixture.Client;
    }

    private List<Asset> GetTestAssets()
    {
        return Startup.GetTestAssets();
    }

    [Fact]
    public async Task Assets_ReturnsAViewResult_WithListOfAssets()
    {
        // Arrange
        var mockRepo = new Mock<IAssetRepository>();
        mockRepo.Setup(repo => repo.ListAsync()).Returns(Task.FromResult(GetTestAssets()));

        try
        {
            var controller = new AssetController(mockRepo.Object);
            // Act
            var result = await controller.Assets();

            // Assert
            var viewResult = Assert.IsType<ViewResult>(result);
            var model = Assert.IsAssignableFrom<IEnumerable<AssetViewModel>>(viewResult.ViewData.Model);
            Assert.Equal(2, model.Count());
        }
        catch (Exception e)
        {
            var msg = e.Message;
        }
    }

    [Fact]
    public async Task Details_ReturnsViewResult_WithOneAsset()
    {
        // Arrange - get an asset known to exist
        var testAssets = Startup.GetTestAssets();
        var id = testAssets.Select(a => a.Id).First();

        // Act
        var response = await _client.GetAsync("/asset/details/" + id);

        // Assert
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();
        Assert.True(responseString.Contains(testAssets.Select(a => a.SerialNumber).First()));
        Assert.True(responseString.Contains(testAssets.Select(a => a.PartNumber).First()));
    }        

    [Fact]
    public async Task PostAsync_ReturnsBadRequest_GivenNullModel()
    {
        // Arrange & Act
        var mockRepo = new Mock<IAssetRepository>();
        var controller = new AssetController(mockRepo.Object);
        controller.ModelState.AddModelError("error", "some error");

        // Act
        var result = await controller.PostAsync(null);

        // Assert
        Assert.IsType<BadRequestObjectResult>(result);
    }
}

这是启动代码:

    public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<AppDbContext>(options => options.UseInMemoryDatabase());

        services.AddMvc();
        services.AddScoped<ITodoRepository, TodoRepository>();
        services.AddScoped<IAssetRepository, AssetRepository>();
        services.AddScoped<IValuesRepository, ValuesRepository>();
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();

            var repository = app.ApplicationServices.GetService<IAssetRepository>();

            InitializeDatabaseAsync(repository).Wait();
        }

        app.UseStaticFiles();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Asset}/{action=Index}/{id?}");
        });
    }

    // Load the database with sample assets
    public async Task InitializeDatabaseAsync(IAssetRepository repo)
    {
        var assetList = await repo.ListAsync();
        if (!assetList.Any())
        {
            foreach (var asset in GetTestAssets())
            {
                await repo.AddAsync(asset);
            }
        }
    }

    public static List<Asset> GetTestAssets()
    {
        return new List<Asset>()
        {
            new Asset("5eb6eb60-72d7-4f51-b209-22a4d97604bd", "SN1234", "PN1234"),
            new Asset("4dc5fd59-98d7-3g34-c310-47g5e84987cg", "SN5678", "PN5678")
        };
    }
}

0 个答案:

没有答案