2016-07-26 5 views
1

私はEntityFrameworkCore 1.0を使用していますが、単純な単体テストをセットアップしようとしていますが、エラーが発生しています "同じキーの項目が既に追加されています。 10.私は、私がなぜ、どのように修正するには問題が何であるかを理解しませんが起きてからこれを防ぐためにどのように理解していないEntityFrameworkコアテスト中メモリデータベースエラー

最初に私のようなものに見えるのテストがあります。。

public void CanLoadAllAnnouncements() 
{ 
    var service = new AnnouncementControllerService(GenerateTestData.Generate()); 

    var results = service.Get(); 
    Assert.Equal(3, results.Count); 
    Assert.Equal("Test Announcement 1", results[0].Message); 
    Assert.Equal("Test Announcement 2", results[1].Message); 
    Assert.Equal("Test Announcement 3", results[2].Message); 
} 

をこれは、生成されているメモリ内のデータベースを渡すコントローラサービスクラスを呼び出していることがわかります。このクラスのコードは次のようになります。

public const string CurrentUserName = "testUserName"; 
    public const string AlternateUserName = "anotherUserName"; 

    public static DataContext Generate() 
    { 
     var context = new DataContext(); 

     CreateRecentActivity(context); 
     CreateAnnouncement(context); 

     context.SaveChanges(); 

     return context; 
    } 

    private static void CreateAnnouncement(DataContext context) 
    { 
     AddAnnouncement(context, -20, "Test Announcement 1", 1); 
     AddAnnouncement(context, -21, "Test Announcement 2", 2); 
     AddAnnouncement(context, -22, "Test Announcement 3", 3); 
    } 

    private static void CreateRecentActivity(DataContext context) 
    { 
     AddRecentActivity(context, -10, "Test Result 1", "#/TestResult1", CurrentUserName); 
     AddRecentActivity(context, -11, "Test Result 2", "#/TestResult2", CurrentUserName); 
     AddRecentActivity(context, -12, "Test Result 3", "#/TestResult3", CurrentUserName); 
     AddRecentActivity(context, -13, "Another Test Result 1", "#/AnotherTestResult1", AlternateUserName); 
     AddRecentActivity(context, -14, "Another Test Result 2", "#/AnotherTestResult2", AlternateUserName); 
     AddRecentActivity(context, -15, "Another Test Result 3", "#/AnotherTestResult3", AlternateUserName); 
    } 

    private static void AddAnnouncement(DataContext context, int id, string message, int ordering) 
    { 
     if (context.Announcements.All(ra => ra.Id != id)) 
     { 
      context.Announcements.Add(new Announcement 
      { 
       Id = id, 
       Message = message, 
       Ordering = ordering 
      }); 
     } 
    } 

    private static void AddRecentActivity(DataContext context, int id, string name, string url, string userName) 
    { 
     if (context.RecentActivities.All(ra => ra.Id != id)) 
     { 
      context.RecentActivities.Add(new RecentActivity 
      { 
       Id = id, 
       Name = name, 
       Url = url, 
       UserName = userName 
      }); 
     } 
    } 

だから、それは単にそれが既に追加されていないことを確認した後DbSetsのそれぞれにカップルの項目を追加して見ることができます。今私がこのテストを実行すると、この時点で一日中問題なく動作します。私は2番目のテスト、あなたがこのテストは前のものと非常に似ていることがわかります。この

public void CanLoadAllRecentItemsForCurrentUser() 
    { 
     var service = new RecentActivityControllerService(GenerateTestData.Generate()); 

     var results = service.Get(Testing.GenerateTestData.CurrentUserName); 
     Assert.Equal(3, results.Count); 
     Assert.Equal("Test Result 1", results[0].Name); 
     Assert.Equal("Test Result 2", results[1].Name); 
     Assert.Equal("Test Result 3", results[2].Name); 
    } 

のようなものを追加するとき

問題が場に出ます。コントローラサービスを作成することと全く同じことを、generateメソッドで構築されたdbコンテキストの新しいインスタンスに渡します。

ここでエラーが発生します。私は、問題は何とかコンテキストが静的なものとして生成されていると仮定しています(ただし、毎回別のインスタンスを生成しています)。また、テストが並行して実行されているため、エラーを引き起こす同じキーを持つ同じ項目を追加しています。

GenerateTestDataクラス(クラス、メソッドなど)で静的でインスタンス変数を使用しているものはすべて削除しようとしましたが、違いはありません。

私はここで何が欠けていますか?私はそれぞれのテストのためにメモリデータベースを別々に生成したいので、それらの間に依存関係はありません。私はリンクでこの答えを見つけた

答えて

4

https://docs.efproject.net/en/latest/miscellaneous/testing.html

基本的な考え方は、あなたがそれをテストごとに別々のクリーンなコンテキストを作成することを確認するために、あなたのデータコンテキストのコンストラクタにDbContextOptionsを指定する必要があるということです。

public static DataContext Generate() 
{ 
    var options = CreateNewContextOptions(); 
    var context = new DataContext(options); 

    CreateRecentActivity(context); 
    CreateAnnouncement(context); 

    context.SaveChanges(); 

    return context; 
} 

private static DbContextOptions<DataContext> CreateNewContextOptions() 
{ 
    // Create a fresh service provider, and therefore a fresh 
    // InMemory database instance. 
    var serviceProvider = new ServiceCollection() 
     .AddEntityFrameworkInMemoryDatabase() 
     .BuildServiceProvider(); 

    // Create a new options instance telling the context to use an 
    // InMemory database and the new service provider. 
    var builder = new DbContextOptionsBuilder<DataContext>(); 
    builder.UseInMemoryDatabase() 
      .UseInternalServiceProvider(serviceProvider); 

    return builder.Options; 
}