2016-12-27 12 views
2

私はWebAPIをビルドしています。私のテストとは別にPostmanで実行していますが、いくつかの統合/ユニットテストを実装したいと思います。XUnit DIでオーバーライドされたスタートアップファイル(.netコア)

私のビジネスロジックは非常に薄く、ほとんどの場合はCRUDアクションが多いので、私は自分のコントローラーをテストしたいと思っていました。

私は基本的な設定があります。リポジトリパターン(インタフェース)、サービス(ビジネスロジック)、コントローラ フローはコントローラ(DIサービス)→サービス(DIレポ)→レポアクションになります。

私のやったことは、メモリデータベースに変更するためのスタートアップファイルを無効にし、残りはうまくいくはずです(サービスが追加され、reposが追加されています)。私の基本的なテストでは問題ありません。

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はありません。

次のコンストラクタのパラメータは、フィクスチャデータに一致していませんでした: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)); 
     } 
    } 
} 

私は行方不明?

+0

IIRCあなたはテストクラスに依存性の注入を使用することはできません。 xunitにはコンストラクタ(https://xunit.github.io/docs/shared-context.htmlクラスとコレクションの備品を参照)を介して特殊なフィクスチャを挿入させるだけです。インテグレーションテストのためには、 'IServiceProvider'のインスタンスを取得してサービスを解決する必要があります。コントローラテストのためには、 'TestServer' class => docs.microsoft.com/en-us/aspnet/core/testing/integration-testing – Tseng

+0

を使う必要があります。また、Startup.csから継承したくないかもしれず、代わりに別のクラス。ブートストラッピングコードを使用してください。特定の構成(つまり、Aの後でBの前にコードを実行する必要がある場合)ではオーバーライドがうまく機能しません。同じサービスを2回登録すると、複数のサービスが登録されているため、 'GetRequiredService'を呼び出すときに例外が発生することがあります(' services.TryAddXxx () ' – Tseng

+0

)。フィクスチャインスタンスからコンストラクタ引数として追加すると、自動的に提供されますので、FixturesではDIを使用できますが、起動時にDIを使用することはできません。まだテストでスタートアップでDIできるのであれば、テストをして数秒で実行できます。 – Drakoumel

答えて

3

テストクラスには依存関係注入を使用できません。 xunitにはコンストラクタ経由で特殊なフィクスチャを挿入させることしかできません(docs参照)。

インテグレーションテストでは、Microsoft.AspNetCore.TestHostパッケージのTestServerクラスと、別のStartup.csクラス(継承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のインスタンスを作成し、テストを実行する必要があります。今

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); 
    } 
} 

データベースへの書き込み操作を呼び出すときに、データが実際にデータベースに書き込まれている場合、あなたもチェックすることができます。

[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); 
} 
+0

あなたは私の質問に私のコメントを回答しました:)私は今晩後にこれを実装しようとします。 ありがとう、これは大きく役立ちます! – Drakoumel

+0

基本クラス 'ConfigureServices'ではなく' ConfigureTestServices'を 'TestServer'に使うにはどうすればいいですか? –

+0

@DmytroBogatov: 'WebHostBuilder'に' .UseEnvironment( "Test")を使用してください – Tseng

関連する問題