【问题标题】:Creating a TestServer and using Dependency Injection with XUnit and ASP.NET Core 1.0创建一个 TestServer 并使用 XUnit 和 ASP.NET Core 1.0 的依赖注入
【发布时间】:2016-06-25 23:57:44
【问题描述】:

我有一个具有以下项目结构的 ASP.NET Core 1.0 解决方案:

Web 应用程序 (ASP.NET MVC6)
BusinessLibrary(类库包)
DataLibrary(类库包)
测试(类库包 w/XUnit

我正在尝试在整个系统中使用微软新的内置依赖注入。

这是当前所有内容从我的 ASP.NET MVC 应用程序一直流到我的存储库层的方式

//Startup.cs of MVC Web App
public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();

    services.AddSingleton(_=> Configuration);

    services.AddTransient<ICustomerService, CustomerService>();
    services.AddTransient<ICustomerRepository, CustomerRepository>();
}

public class CustomersController : Controller
{
    private ICustomerService _service;
    public CustomersController(ICustomerService service)
    {
        _service= service;
    }
}

public class CustomerService : ICustomerService
{
    private ICustomerRepository _repository;
    public PriceProtectionManager(ICustomerRepository repository)
    {
        _repository = repository;
    }
}

public class CustomerRepository : BaseRepository, ICustomerRepository
{
    public CustomerRepository(IConfigurationRoot config) 
    : base(config)
    {
    }
}

public class BaseRepository
{
    private IConfigurationRoot _config;

    public BaseRepository(IConfigurationRoot config)
    {
        _config = config;
    }
}

现在我怎样才能获得与 XUnit 项目类似的东西,以便我可以访问 CustomerService 并调用函数?

这是我的 Fixture 类的样子:

public class DatabaseFixture : IDisposable
{
    public ICustomerService CustomerService;
    public DatabaseFixture(ICustomerService service)
    {
        CustomerService = service;
    }

    public void Dispose()
    {

    }
}

问题是 ICustomerService 无法解决...这可能是因为我没有像我的 WebApp 这样的 Startup.cs。如何在测试项目中复制这种行为?我不知道在哪里创建我的 TestServer,因为如果我在夹具中创建它将为时已晚。

【问题讨论】:

  • 为什么不使用 ASP.NET 附带的typed options framework?这允许您只注入一个IOptions&lt;T&gt;
  • @DannyvanderKraan 请查看我对您其他帖子的评论。此外,请参阅我对当前代码的帖子所做的更新。
  • @HenkMollema 你能详细说明一下吗?请参阅我的更新帖子,了解我的 MVC 应用程序当前如何使用 DI 深入到存储库层。
  • @DannyvanderKraan 很抱歉再次打扰您,但请您看看我的编辑,看看一切如何从我的 MVC Web 应用程序流向存储库层,然后是我当前的夹具类的样子。夹具基本上相当于我的asp.net mvc应用程序中的Controller。

标签: c# asp.net asp.net-core xunit asp.net-core-1.0


【解决方案1】:

好吧,您可以为您的 SUT 提供您自己的依赖项(恕我直言,这是您应该想要的方式)。我刚刚回答了一个类似的问题here

如果你想在一个地方定义你的连接字符串,你可以使用 xUnit 的能力来使用shared context(fixtures)。

更新: 包含夹具和 DI 的示例...

您的测试类应该实现 IClassFixture 并包含例如以下字段和构造函数:

    public class AspnetCoreAndXUnitPrimeShould: IClassFixture<CompositionRootFixture>
{
    private readonly TestServer _server;
    private readonly HttpClient _client;
    private readonly CompositionRootFixture _fixture;

    public AspnetCoreAndXUnitPrimeShould(CompositionRootFixture fixture) 
    {
        // Arrange
        _fixture = fixture;
        _server = new TestServer(TestServer.CreateBuilder(null, app =>
        {
            app.UsePrimeCheckerMiddleware();
        },
            services =>
            {
                services.AddSingleton<IPrimeService, NegativePrimeService>();
                services.AddSingleton<IPrimeCheckerOptions>(_ => new AlternativePrimeCheckerOptions(_fixture.Path));
            }));
        _client = _server.CreateClient();
    }

请注意,AspnetCoreAndXUnitPrimeShould 是我示例中测试类的名称。夹具看起来像:

    public class CompositionRootFixture
{
    public string Path { get; }

    public CompositionRootFixture()
    {
        Path = "@/checkprime";
    }
}

这只是对另一个示例的快速采用,但您现在应该了解如何解决您的问题。 AlternativePrimeCheckerOptions 在构造函数中接受一个字符串,就像您的 Configuration 类一样。使用夹具,您可以将这个连接字符串安排在一个地方。

更新 示例:https://github.com/DannyvanderKraan/ASPNETCoreAndXUnit

【讨论】:

  • 我认为我们走在正确的轨道上,但我可以举一个结合夹具和 DI 的例子吗?
  • 丹尼非常感谢这个例子。我不知道你是否注意到,但我是另一个帖子的同一个人。可能不应该打开两个。您是否有机会在 github 上加载一个向我展示的示例:如果我有“IProductRepo”和“ProductRepo”,我如何使用 DI 在我的测试类中访问 ProductRepo 的实例?甚至在在这里发帖之前,我尝试结合使用 Xunit 共享上下文文档和 ASP.NET Core 1.0 集成测试文档。仍然无法找到一个可行的解决方案。
  • 我只想做类似的事情: private IProductRepo _productRepo= new ProductRepo();在我的测试类的顶部,但诀窍是我的 ProductRepo 要求注入 IConfigurationRoot,因为我将它用于我的连接字符串。
  • 布莱克,是的,我后来注意到了。答案确实几乎相同。首先只需将 IConfigurationRoot 添加到 TestServer 的服务中。然后让 ProductRepo 通过其构造函数请求 IConfigruationRoot 的实例,并将其添加到 TestServer 的同一服务集合中。并且底层的依赖注入容器将处理依赖的注入。就夹具而言,我注入了一个“路径”,您可以注入一个“连接字符串”或任何相同的方式。请参阅更新以获取示例。
  • 我没有 UsePrimeCheckerMiddleware.. 在 CompositionRootFixture 类中,智能感知在 ContainerBuilder、RegisterInstance 和 Resolve 上出错。这些是 AutoFac 吗?因为我没有使用 AutoFac。我不应该像上面的示例那样向 TestServer 传递来自我的 Tests 项目的 Startup.cs 文件吗?我只是不明白 DI 是如何从 ASP.NET 应用程序一直到我的存储库的如此顺利的工作,并且使它从我的单元测试流到存储库是非常不同的。
猜你喜欢
  • 2016-06-26
  • 2020-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多