通过覆盖的启动文件(.net核心)的XUnit DI [英] XUnit DI through overridden Startup file (.net core)
问题描述
我已经构建了一个WebAPI,除了我在Postman上运行的测试之外,我还想实现一些集成/单元测试.
I have build a WebAPI and apart from my tests running on Postman I would like to implement some Integration/Unit tests.
现在,我的业务逻辑非常薄,大多数情况下,它的CRUD操作更多,因此我想从测试我的Controllers开始.
Now my business logic is very thin, most of the time its more of CRUD actions, therefore I wanted to start with testing my Controllers.
我有一个基本设置.存储库模式(接口),服务(业务逻辑)和控制器. 流程进入控制器(DI服务)->服务(DI回购)->回购操作!
I have a basic setup. Repository pattern (interfaces), Services (business logic) and Controllers. The flow goes Controller (DI Service) -> Service (DI Repo) -> Repo Action!
所以我所做的是重写我的启动文件以将其更改为内存数据库,其余的应该没问题(我会假设),添加了服务,添加了回购协议,现在我指向的是内存数据库,这很好用于我的基本测试.
So what I did was override my Startup file to change into a in memory database and the rest should be fine (I would assume) Services are added, repos are added and now I am pointing into a in memory DB which is fine for my basic testing.
namespace API.UnitTests
{
public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env)
: base(env)
{
}
public void ConfigureTestServices(IServiceCollection services)
{
base.ConfigureServices(services);
//services.Replace<IService, IMockedService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
base.Configure(app, env, loggerFactory);
}
public override void SetUpDataBase(IServiceCollection services)
{
var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = ":memory:" };
var connectionString = connectionStringBuilder.ToString();
var connection = new SqliteConnection(connectionString);
services
.AddEntityFrameworkSqlite()
.AddDbContext<ApplicationDbContext>(
options => options.UseSqlite(connection)
);
}
}
}
我写了我的第一个测试,但是不存在DatasourceService:
I wrote my first test, but the DatasourceService is not there:
以下构造函数参数没有匹配的灯具数据:DatasourceService datasourceService
The following constructor parameters did not have matching fixture data: DatasourceService datasourceService
namespace API.UnitTests
{
public class DatasourceControllerTest
{
private readonly DatasourceService _datasourceService;
public DatasourceControllerTest(DatasourceService datasourceService)
{
_datasourceService = datasourceService;
}
[Xunit.Theory,
InlineData(1)]
public void GetAll(int companyFk) {
Assert.NotEmpty(_datasourceService.GetAll(companyFk));
}
}
}
我想念什么?
推荐答案
您不能在测试类上使用依赖项注入.您只能让xunit通过构造函数注入特殊的夹具(请参见 docs ).
You can't use dependency injection on test classes. You can only let xunit inject special fixtures via constructor (see docs).
对于集成测试,您想使用Microsoft.AspNetCore.TestHost
包中的TestServer
类和一个单独的Startup.cs
类(比继承imho更容易设置配置).
For Integration Testing you want to use the TestServer
class from Microsoft.AspNetCore.TestHost
package and a separate Startup.cs
class (easier to setup configuration than inheritance imho).
public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureTestServices(IServiceCollection services)
{
services.Replace(ServiceDescriptor.Scoped<IService, MockedService>());
services.AddEntityFrameworkSqlite()
.AddDbContext<ApplicationDbContext>(
options => options.UseSqlite(connection)
);
}
public void Configure(IApplicationBuilder app)
{
// your usual registrations there
}
}
在单元测试项目中,您需要创建TestServer
的实例并执行测试.
In your unit test project, you need to create an instance of the TestServer
and perform the test.
public class DatasourceControllerTest
{
private readonly TestServer _server;
private readonly HttpClient _client;
public DatasourceControllerTest()
{
// Arrange
_server = new TestServer(new WebHostBuilder()
.UseStartup<TestStartup>());
_client = _server.CreateClient();
}
[Xunit.Theory,
InlineData(1)]
public async Task GetAll(int companyFk) {
// Act
var response = await _client.GetAsync($"/api/datasource/{companyFk}");
// expected result from rest service
var expected = @"[{""data"":""value1"", ""data2"":""value2""}]";
// Assert
// This makes sure, you return a success http code back in case of 4xx status codes
// or exceptions (5xx codes) it throws an exception
response.EnsureSuccessStatusCode();
var resultString = await response.Content.ReadAsStringAsync();
Assert.Equals(resultString, expectedString);
}
}
现在,当您调用写入数据库的操作时,您还可以检查数据是否确实写入了数据库:
Now, when you call operations which write to the database, you can also check if the data is really written to the database:
[Xunit.Theory,
InlineData(1)]
public async Task GetAll(int companyFk) {
// Act
var response = await _client.DeleteAsync($"/api/datasource/{companyFk}");
// expected result from rest service
// Assert
response.EnsureSuccessStatusCode();
// now check if its really gone in the database. For this you need an instance
// of the in memory Sqlite DB. TestServer has a property Host, which is an IWebHost
// and it has a property Services which is the IoC container
var provider = _server.Host.Services;
var dbContext = provider.GetRequiredService<ApplicationDbContext>();
var result = await dbContext.YourTable.Where(entity => entity.Id == companyFk).Any();
// if it was deleted, the query should result in false
Assert.False(result);
}
这篇关于通过覆盖的启动文件(.net核心)的XUnit DI的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!