创建 TestServer 并使用 XUnit 和 ASP.NET Core 1.0 的依赖注入

Bla*_*ell 5 c# asp.net xunit asp.net-core asp.net-core-1.0

我有一个 ASP.NET Core 1.0 解决方案,其项目结构如下:

Web 应用程序 (ASP.NET MVC6)
BusinessLibrary(类库包)
DataLibrary(类库包)测试(带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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

这是我的 Fixture 类的样子:

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

    public void Dispose()
    {

    }
}
Run Code Online (Sandbox Code Playgroud)

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

Dan*_*aan 3

好吧,您可以向您的 SUT 提供您自己的依赖项(恕我直言,这就是您应该希望的方式)。我刚刚在这里回答了类似的问题。

如果您想在一处定义连接字符串,您可以使用 xUnit 的共享上下文(固定装置)功能。

更新:结合夹具和 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();
    }
Run Code Online (Sandbox Code Playgroud)

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

    public class CompositionRootFixture
{
    public string Path { get; }

    public CompositionRootFixture()
    {
        Path = "@/checkprime";
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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