1

Я успешно вложил зависимости, используя Moq в моем модульном тестовом проекте. Но для теста интеграции я хотел бы взаимодействовать с базой данных. Поэтому я не могу подделывать репозитории/зависимости. У меня возникли проблемы с тем, как добиться такой цели в отдельной библиотеке классов, внедренной для тестирования интеграции.Инъекция зависимостей в тестировании ядра Asp.net

Я хотел бы сделать что-то вроде этого (данные должны поступать из базы данных):

public class CountryServiceIntegrationTest 
{ 

    private ICountryService countryService; 

    public CountryServiceIntegrationTest(ICountryService _countryService) 
    { 
     countryService = _countryService;      
    } 

    #endregion 


    [Fact] 
    public void Should_Return_ListOf_Countries() 
    { 
     //Act 
     var myList = countryService.GetList("A"); 
     //Assert 
     Assert.True(myList.Count > 0); 
    }   
} 

Мой CountryService Класс:

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 
     }).ToList(); 
    } } 

Ну я отдельный класс проекта библиотеки МОК, где зависимостей регистрируются. Затем он регистрируется в классе Startup.cs. Поскольку класс Startup.cs не запускается во время тестов, зависимости не вводятся. Итак, как я могу решить эту проблему?

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

Ну теперь: Я последовал this ссылку и сделал в соответствии с ним. Мне кажется, что был вызван класс запуска, который также вызывает ConfigureDependency.RegisterDependencies (..).

испытаний Класс:

public CountryServiceIntegrationTest() 
    { 
     _server = new TestServer(new WebHostBuilder() 
      .UseStartup<Startup>()); 
     _client = _server.CreateClient();    
    } 

    [Fact] 
    public async Task ReturnHelloWorld() 
    { 
     //Act 
     var response = await _client.GetAsync("/home/Test"); 
     response.EnsureSuccessStatusCode(); 

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

     //Assert 
     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>(); 
     services.AddSingleton<ActivityLog>(); 
     // Add framework services. 
     services.AddMvc(); 
     // Register Database Connection String 
     var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]); 
     services.AddSingleton<IConnectionSetting>(connectionSetting); 
     services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); 
     services.AddSingleton<IActionContextAccessor, ActionContextAccessor>(); 
     // Fill other dependencies 
     var configureDependency = new ConfigureDependency(); 
     configureDependency.RegisterDependencies(services, connectionSetting);   

    } 

ConfigureDependency.RegisterDependency (..):

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.............. 

    } 
} 

Но теперь, что происходит, я получаю эту ошибку: enter image description here

С Startup.cs вызывается который затем вызывает класс ConfigureDependency, это не означает, что параметры (услуги, connectionSetting) должны передаваться автоматически. Это (ConfigureDependency.RegisterDependencies (..)), где я получаю сообщение об ошибке.

+0

Вызвать класс запуска во время модульного испытания. – Nkosi

+1

Взгляните на собственный функциональный испытательный прибор MVC для тестов интеграции: https://github.com/aspnet/Mvc/blob/dev/test/Microsoft.AspNetCore.Mvc.FunctionalTests/MvcTestFixture.cs ... Ваша проблема кажется быть связанным с конфигурацией, неспособной найти ключ строки подключения, не так ли? Можете ли вы показать, как вы заполняете конфигурацию? –

ответ

0

Это в методе useSqlServerArgumentNullException:

Кажется, что connectionSetting.Get() возвращается null.

В следующем коде

var connectionSetting = new ConnectionSetting(Configuration["Data:ConnectionStrings:DefaultConnection"]); 
services.AddSingleton<IConnectionSetting>(connectionSetting); 

Это предполагает, что ConnectionSetting реализует интерфейс IConnectionSetting так почему не использовать непосредственно экземпляр вместо вызова Get() на нем?

Как показано ниже:

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

Дополнительные замечания:
Это действительно зависит от того, что вы подразумеваете под integration test.Это может относится к:

  • выше модульных тестов уровня (в отличие от модульных тестов, ограниченных к одному классу, такие интеграционные тесты будут тестировать интеграцию между различными классами).
  • тесты интеграции уровня пространства имен (протестируйте один или несколько общедоступных интерфейсов из заданного пространства имен без проверки внутренних классов).
  • тесты интеграции уровня сборки (такие же, как пространство имен, но с областью сборки).
  • тесты интеграции черного ящика (проверьте полное программное обеспечение на его взаимодействие с внешней системой точки зрения). ASP.NET integration testing documentation связан с этим типом теста.

Это часто лучше иметь несколько слоев тесты покрытые, прежде чем пытаться сделать тестирование больших взрыва ... но это вопрос компромисса между временем и качеством.

Для того, чтобы сделать интеграцию не столь высокого уровня испытаний возможно/легко написать:

  • Вы не должны разделять ту же среду базы данных между тестами и код продукции (так не одна и та же строка соединения).

  • Вы не должны использовать Startup, поскольку он предназначен для имитации всего веб-сайта на тестовом сервере.

  • Регистрация и разрешение услуг должны быть разделены на некоторые согласованные конкретные классы, чтобы упростить интеграционные тесты на конкретных деталях.

Смежные вопросы