简体   繁体   English

Xunit 测试 EFcore 存储库 InMemory DB

[英]Xunit Testing EFcore Repositories InMemory DB

I am trying to unit test the repositories, I am using InMemory option in EFCore.我正在尝试对存储库进行单元测试,我在 EFCore 中使用 InMemory 选项。 This is the method这是方法

    [Fact]
    public async Task GetCartsAsync_Returns_CartDetail()
    {
        ICartRepository sut = GetInMemoryCartRepository();
        CartDetail cartdetail = new CartDetail()
        {
            CommercialServiceName = "AAA"
        };

        bool saved = await sut.SaveCartDetail(cartdetail);

        //Assert  
        Assert.True(saved);
        //Assert.Equal("AAA", CartDetail[0].CommercialServiceName);
        //Assert.Equal("BBB", CartDetail[1].CommercialServiceName);
        //Assert.Equal("ZZZ", CartDetail[2].CommercialServiceName);
    }


    private ICartRepository GetInMemoryCartRepository()
    {
        DbContextOptions<SostContext> options;
        var builder = new DbContextOptionsBuilder<SostContext>();
        builder.UseInMemoryDatabase($"database{Guid.NewGuid()}");
        options = builder.Options;
        SostContext personDataContext = new SostContext(options);
        personDataContext.Database.EnsureDeleted();
        personDataContext.Database.EnsureCreated();
        return new CartRepository(personDataContext);
    }

I am getting error which say我收到错误消息

   System.TypeLoadException : Method 'ApplyServices' in type 
   'Microsoft.EntityFrameworkCore.Infrastructure.Internal.InMemoryOptionsExtension' from assembly 
   'Microsoft.EntityFrameworkCore.InMemory, Version=1.0.1.0, Culture=neutral, 
   PublicKeyToken=adb9793829ddae60' does not have an implementation.


   Microsoft. 
  EntityFrameworkCore.InMemoryDbContextOptionsExtensions.UseInMemoryDatabase(DbContextOptionsBuilder 
   optionsBuilder, String databaseName, Action`1 inMemoryOptionsAction)


    Microsoft.EntityFrameworkCore.InMemoryDbContextOptionsExtensions.UseInMemoryDatabase[TContext] 
   (DbContextOptionsBuilder`1 optionsBuilder, String databaseName, Action`1 inMemoryOptionsAction)

My reference is from https://www.carlrippon.com/testing-ef-core-repositories-with-xunit-and-an-in-memory-db/我的参考来自https://www.carlrippon.com/testing-ef-core-repositories-with-xunit-and-an-in-memory-db/

Please suggest me where i am going wrong with the current implementation.请建议我当前的实施哪里出了问题。 Thanks in Advance提前致谢

I suggest reading the official Microsoft documentation about integration testing.我建议阅读有关集成测试的官方 Microsoft 文档。

https://docs.microsoft.com/fr-fr/aspnet/core/test/integration-tests?view=aspnetcore-3.0 https://docs.microsoft.com/fr-fr/aspnet/core/test/integration-tests?view=aspnetcore-3.0

Secondly, I you start adding this kind of boilerplate to create your tests with the memory database you will stop doing it very soon.其次,我开始添加这种样板来使用 memory 数据库创建测试,你很快就会停止这样做。

For integration tests, you should be near to your development configuration.对于集成测试,您应该靠近您的开发配置。

Here my configuration files and a usage in my CustomerController:这是我的配置文件和我的 CustomerController 中的用法:

Integration Startup File集成启动文件

Have all think about database creation and dependency injection都考虑过数据库创建和依赖注入

public class IntegrationStartup : Startup
    {
        public IntegrationStartup(IConfiguration configuration) : base(configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public override void ConfigureServices(IServiceCollection services)
        {
            services.AddEntityFrameworkInMemoryDatabase().BuildServiceProvider();

            services.AddDbContext<StreetJobContext>(options =>
            {
                options.UseInMemoryDatabase("InMemoryAppDb");
            });


            //services.InjectServices();
            //here you can set your ICartRepository DI configuration


            services.AddMvc(option => option.EnableEndpointRouting = false)
                .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
                .AddApplicationPart(Assembly.Load(new AssemblyName("StreetJob.WebApp")));

            ConfigureAuthentication(services);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public override void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            var serviceScopeFactory = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>();
            using (var serviceScope = serviceScopeFactory.CreateScope())
            {
                //Here you can add some data configuration
            }

            app.UseMvc();
        }

The fake startup虚假的启动

it's quite similar to the one in the Microsoft documentation它与 Microsoft 文档中的非常相似

public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
    protected override IWebHostBuilder CreateWebHostBuilder()
    {
        return WebHost.CreateDefaultBuilder(null)
            .UseStartup<TStartup>();
    }

    protected override void ConfigureWebHost(IWebHostBuilder builder)
    {
        builder.UseSolutionRelativeContentRoot(Directory.GetCurrentDirectory());

        builder.ConfigureAppConfiguration(config =>
        {
            config.AddConfiguration(new ConfigurationBuilder()
               //custom setting file in the test project
                .AddJsonFile($"integrationsettings.json")
                .Build());
        });

        builder.ConfigureServices(services =>
        {
        });
    }
}

The controller controller

public class CustomerControllerTest : IClassFixture<CustomWebApplicationFactory<IntegrationStartup>>
    {
        private readonly HttpClient _client;
        private readonly CustomWebApplicationFactory<IntegrationStartup> _factory;
        private readonly CustomerControllerInitialization _customerControllerInitialization;
        public CustomerControllerTest(CustomWebApplicationFactory<IntegrationStartup> factory)
        {
            _factory = factory;
            _client = _factory.CreateClient();
        }
}

With this kind of setting, testing the integration tests are very similar to the development controller.使用这种设置,测试集成测试与开发 controller 非常相似。 It's a quite good configuration for TDD Developers.对于 TDD 开发人员来说,这是一个相当不错的配置。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM