首页 文章

Asp.net核心集成测试中的依赖注入

提问于
浏览
1

我在单元测试项目中使用Moq成功注入了依赖项 . 但是对于集成测试,我想与数据库进行交互 . 所以我敢于伪造存储库/依赖项 . 我在为集成测试引入的单独类库中遇到了如何实现这样的问题 .

我想做这样的事情(数据应该来自数据库):

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);
    }        
}

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

好吧,我有单独的IOC类库项目,其中注册了依赖项 . 然后在Startup.cs类中注册它 . 由于在测试期间未调用Startup.cs类,因此不会注入依赖项 . 那么我该如何解决这个问题呢?

------更新根据官方文件中的指导原则-----

那么现在:我跟着this链接并按照它做了 . 在我看来,调用了Startup类,它也调用了ConfigureDependency.RegisterDependencies(..) .

Test Class:

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类,这并不意味着应自动传递参数(services,connectionSetting) . 这是(ConfigureDependency.RegisterDependencies(..))我收到错误 .

1 回答

  • 1

    It's an ArgumentNullException in the useSqlServer method:

    似乎 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))
    

    Additional Remarks:
    这真的取决于你的意思integration test . 它可以指:

    • higher level unit tests (与仅限于一个类的单元测试相反,此类集成测试将测试不同类之间的集成) .

    • namespace level integration tests (在不检查内部类的情况下测试给定命名空间中的一个或多个公共接口) .

    • assembly level integration tests (与命名空间相同但具有装配范围) .

    • black box integration tests (从外部系统的角度测试完整软件的交互) . ASP.NET integration testing documentation与此类测试有关 .

    它通常更好 have several layers test-covered before trying to do the Big Bang testing ......但这是 tradeoff between time and quality 的问题 .

    为了使不那么高级别的集成测试成为可能/易于编写:

    您的测试和 生产环境 代码之间的

    • You should not share the same database environment (因此不是相同的连接字符串) .

    • you shouldn't use Startup 因为它旨在模仿测试服务器上的整个网站 .

    • Registration and Resolution 服务应该在一些连贯的特定类中拆分,以便更容易地对特定部分进行集成测试 .

相关问题