简体   繁体   中英

Xunit Testing EFcore Repositories InMemory DB

I am trying to unit test the repositories, I am using InMemory option in EFCore. 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/

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.

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.

For integration tests, you should be near to your development configuration.

Here my configuration files and a usage in my 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

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

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. It's a quite good configuration for TDD Developers.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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