Ответ 1
Вы смешиваете юнит-тест с интеграционным тестом. TestServer
предназначен для тестирования интеграции, и если вы хотите повторно использовать класс Startup
, чтобы снова избежать зависимостей регистра, вам следует использовать HttpClient
и сделать HTTP-вызов к контроллеру и действию, которое использует IDepartmentAppService
.
Если вы хотите выполнить модульное тестирование, вам нужно настроить DI и зарегистрировать все необходимые зависимости для тестирования IDepartmentAppService
.
Использование DI через Test Fixture:
public class DependencySetupFixture
{
public DependencySetupFixture()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddDbContext<SharedServicesContext>(options => options.UseInMemoryDatabase(databaseName: "TestDatabase"));
serviceCollection.AddTransient<IDepartmentRepository, DepartmentRepository>();
serviceCollection.AddTransient<IDepartmentAppService, DepartmentAppService>();
ServiceProvider = serviceCollection.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
public class DepartmentAppServiceTest : IClassFixture<DependencySetupFixture>
{
private ServiceProvider _serviceProvide;
public DepartmentAppServiceTest(DependencySetupFixture fixture)
{
_serviceProvide = fixture.ServiceProvider;
}
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
using(var scope = _serviceProvider.CreateScope())
{
// Arrange
var context = scope.ServiceProvider.GetServices<SharedServicesContext>();
context.Department.Add(new Department { DepartmentId = 2, DepartmentCode = "123", DepartmentName = "ABC" });
context.SaveChanges();
var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();
// Act
var departmentDto = await departmentAppService.GetDepartmentById(2);
// Arrange
Assert.Equal("123", departmentDto.DepartmentCode);
}
}
}
Использование внедрения зависимостей в модульном тесте не очень хорошая идея, и вам следует избегать этого. кстати, если вы не хотите повторять себя для регистрации зависимостей, вы можете обернуть свою конфигурацию DI в другой класс и использовать этот класс где угодно.
Использование DI через Startup.cs:
public class IocConfig
{
public static IServiceCollection Configure(IServiceCollection services, IConfiguration configuration)
{
serviceCollection
.AddDbContext<SomeContext>(options => options.UseSqlServer(configuration["ConnectionString"]));
serviceCollection.AddScoped<IDepartmentRepository, DepartmentRepository>();
serviceCollection.AddScoped<IDepartmentAppService, DepartmentAppService>();
.
.
.
return services;
}
}
в классе Startup
и методе ConfigureServices
просто используйте класс IocConfig
:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
IocConfig.Configure(services, configuration);
services.AddMvc();
.
.
.
если вы не хотите использовать класс IocConfig
, измените ConfigureServices
на класс Startup
:
public IServiceCollection ConfigureServices(IServiceCollection services)
{
.
.
.
return services;
и в тестовом проекте повторно используйте класс IocConfig
или Startup
:
public class DependencySetupFixture
{
public DependencySetupFixture()
{
var builder = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", false, true));
configuration = builder.Build();
var services = new ServiceCollection();
// services = IocConfig.Configure(services, configuration)
// or
// services = new Startup(configuration).ConfigureServices(services);
ServiceProvider = services.BuildServiceProvider();
}
public ServiceProvider ServiceProvider { get; private set; }
}
и в методе теста:
[Fact]
public async Task Get_DepartmentById_Are_Equal()
{
using (var scope = _serviceProvider.CreateScope())
{
// Arrange
var departmentAppService = scope.ServiceProvider.GetServices<IDepartmentAppService>();
// Act
var departmentDto = await departmentAppService.GetDepartmentById(2);
// Arrange
Assert.Equal("123", departmentDto.DepartmentCode);
}
}