Dependency Injection in core Integration testing dependency-injection entity-framework-core integration-testing testing


I successfully injected dependencies using Moq in my unit test project. But for the integration testI would like to interact with the database. So I canot fake the repositories/ dependencies. I am having trouble how to achieve such thing in seperate class library introduced for integration testing.

I would like to do something like this (data should come from database):

public class CountryServiceIntegrationTest

    private ICountryService countryService;

    public CountryServiceIntegrationTest(ICountryService _countryService)
        countryService = _countryService;                     


    public void Should_Return_ListOf_Countries()
        var myList = countryService.GetList("A");
        Assert.True(myList.Count > 0);

My CountryService Class:

public class CountryService : ICountryService
    // Note: Have to use Core.Domain.Country because of the namespace has Quantum.Service.Country
    protected IRepository<Core.Domain.Country> _countryRepository;
    protected IRepository<Core.Domain.State> _stateRepository;
    protected IRepository<Core.Domain.City> _cityRepository;

    public CountryService(IRepository<Core.Domain.Country> countryRepository, IRepository<Core.Domain.State> stateRepository, IRepository<Core.Domain.City> cityRepository)
        _countryRepository = countryRepository;
        _stateRepository = stateRepository;
        _cityRepository = cityRepository;

    public IList<CountryViewModel> GetList(string name)
        var query = _countryRepository.Table.AsQueryable();
        if (string.IsNullOrEmpty(name) == false)
            query = query.Where(i => i.CountryName.StartsWith(name));
        return query.Select(i => new CountryViewModel()
            CountryCode = i.CountryCode,
            CountryName = i.CountryName,
            Currency = i.Currency,
            CurrencyName = i.CurrencyName,
            CurrencySymbol = i.CurrencySymbol,
            TelephoneCountryCode = i.TelephoneCountryCode,
            UnitOfMeasure = i.UnitOfMeasure
    } }

Well I have separate IOC class library project where dependencies are registered. This is then registered in the Startup.cs class. Since Startup.cs class isn't invoked during the tests, the dependencies aren't injected. So how can I solve this problem?

------UPDATED As per guidelines found in official documentation here -----

Well now: I followed this link and did as per it. It seems to me that Startup class was called which also calls the ConfigureDependency.RegisterDependencies(..).

Test Class:

    public CountryServiceIntegrationTest()
        _server = new TestServer(new WebHostBuilder()
        _client = _server.CreateClient();            

    public async Task ReturnHelloWorld()
        var response = await _client.GetAsync("/home/Test");

        var responseString = await response.Content.ReadAsStringAsync();

        Assert.Equal("test", responseString);

Startup.ConfigureServices() :

    public IConfigurationRoot Configuration { get; }

    //gets called in the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)

        //services.AddSingleton<ILogUserActivityService, LogUserActivityService>();
        // Add framework services.
        // Register Database Connection String
        var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
        // Fill other dependencies
        var configureDependency = new ConfigureDependency();
        configureDependency.RegisterDependencies(services, connectionSetting);          



 public class ConfigureDependency
    public IDatabaseFactory DatabaseFactory { get; set; }
    public void RegisterDependencies(IServiceCollection services, IConnectionSetting connectionSetting)

        services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting.Get()));

        services.AddTransient<IDatabaseFactory, DatabaseFactory>();
        services.AddTransient<IDbContext, TestDbContext>();
        services.AddTransient<IDbContext, QuantumDbContext>();

        ...........service n repositories  are registered here..............


But now what happens is I get this error: enter image description here

Since Startup.cs is invoked which then calls the ConfigureDependency class, doesn't it mean that parameters(services, connectionSetting) shall be passed automatically. This is (ConfigureDependency.RegisterDependencies(..)) where I am getting an error.

7/19/2016 11:43:16 AM

Popular Answer

It's an ArgumentNullException in the useSqlServer method:

It seems that connectionSetting.Get() returns null.

In the following code

var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]);

It suggests that ConnectionSetting implements the interface IConnectionSetting so why didn't you use directly the instance instead of calling Get() on it ?

Like below:

services.AddDbContext<QuantumDbContext>(options => options.UseSqlServer(connectionSetting))

Additional Remarks:
It really depends on what you do mean by integration test. It could refers to:

  • higher level unit tests (as opposed to unit tests limited to one class, such integration tests will test integration between different classes).
  • namespace level integration tests (test one or several public interfaces from a given namespace without checking inner classes).
  • assembly level integration tests (same as namespace but with an assembly scope).
  • black box integration tests (test the full software on its interactions fr om the external systems point-of-view). The ASP.NET integration testing documentation is related to this kind of test.

It's often better to have several layers test-covered before trying to do the Big Bang testing... but it's a matter of tradeoff between time and quality.

In order to make the not so high level integration tests possible/easy to write:

  • You should not share the same database environment between your tests and your production code (so not the same connection string).

  • you shouldn't use Startup as it's designed to mimics the whole website on a test server.

  • Registration and Resolution of services should be splitted up in some coherent specific classes to make integration tests on specific parts easier.

9/13/2016 1:03:20 PM

Related Questions


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow