このチュートリアルに従っています
Entity Framework CoreおよびSQL Serverとの統合テスト
私のコードはこのようになります
統合テストクラス
public class ControllerRequestsShould : IDisposable
{
private readonly TestServer _server;
private readonly HttpClient _client;
private readonly YourContext _context;
public ControllerRequestsShould()
{
// Arrange
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.BuildServiceProvider();
var builder = new DbContextOptionsBuilder<YourContext>();
builder.UseSqlServer($"Server=(localdb)\\mssqllocaldb;Database=your_db_{Guid.NewGuid()};Trusted_Connection=True;MultipleActiveResultSets=true")
.UseInternalServiceProvider(serviceProvider);
_context = new YourContext(builder.Options);
_context.Database.Migrate();
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")));
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnListOfObjectDtos()
{
// Arrange database data
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 1, Code = "PTF0001", Name = "Portfolio One" });
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 2, Code = "PTF0002", Name = "Portfolio Two" });
// Act
var response = await _client.GetAsync("/api/route");
response.EnsureSuccessStatusCode();
// Assert
var result = Assert.IsType<OkResult>(response);
}
public void Dispose()
{
_context.Dispose();
}
私が理解しているように、.UseStartUp
メソッドはTestServer
が私のスタートアップクラスを使用することを保証します
私が抱えている問題は、私のActステートメントがヒットしたときに
var response = await _client.GetAsync("/api/route");
スタートアップクラスで、接続文字列がnullであるというエラーが発生します。私の問題の理解は、コントローラーがクライアントからヒットされると、データリポジトリを挿入し、それがデータベースコンテキストを挿入するということです。
テストで作成されたコンテキストを使用するように、new WebHostBuilder
セクションの一部としてサービスを構成する必要があると思います。しかし、これを行う方法がわかりません。
Startup.csのConfigureServicesメソッド
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
});
// Db context configuration
var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
services.AddDbContext<YourContext>(options => options.UseSqlServer(connectionString));
// Register services for dependency injection
services.AddScoped<IYourRepository, YourRepository>();
}
2つのオプションがあります。
WebHostBuilder.ConfigureServices
を使用しますWebHostBuilder.ConfigureServices
をWebHostBuilder.UseStartup<T>
と組み合わせて使用して、WebアプリケーションのDI登録をオーバーライドおよびモックします。
_server = new TestServer(new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddScoped<IFooService, MockService>();
})
.UseStartup<Startup>()
);
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//use TryAdd to support mocking IFooService
services.TryAddTransient<IFooService, FooService>();
}
}
ここで重要なのは、元のTryAdd
クラス内でStartup
メソッドを使用することです。カスタムWebHostBuilder.ConfigureServices
は、元のStartup
の前にbeforeと呼ばれるため、モックは元のサービスの前に登録されます。 TryAdd
は、同じインターフェースがすでに登録されている場合は何もしません。したがって、実際のサービスには触れられません。
詳細: ASP.NET Coreアプリの統合テストの実行 。
ASP.NET Core DIを再構成するためのTestStartup
クラスを作成します。 Startup
から継承して、必要なメソッドのみをオーバーライドできます。
public class TestStartup : Startup
{
public TestStartup(IHostingEnvironment env) : base(env) { }
public override void ConfigureServices(IServiceCollection services)
{
//mock DbContext and any other dependencies here
}
}
あるいは、TestStartup
を最初から作成して、テストをよりクリーンに保つことができます。
そして、それをUseStartup
で指定して、テストサーバーを実行します。
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
これは完全に大きな例です: インメモリデータベースを使用したASP .NETコアアプリの統合テスト 。
@ ilya-chumakovの答えは素晴らしいです。オプションをもう1つ追加したい
。WebHostBuilderExtensionsのConfigureTestServicesメソッドを使用します。
メソッドConfigureTestServicesは、Microsoft.AspNetCore.TestHostバージョン2.1(20.05.2018ではRC1-final)で使用できます。そして、モックで既存の登録を上書きすることができます。
コード:
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureTestServices(services =>
{
services.AddTransient<IFooService, MockService>();
})
);