mardi 26 juillet 2016

EntityFramework Core Testing In Memory Database error

I'm using EntityFrameworkCore 1.0 and trying to setup some simple unit tests, but keep getting an error, something to the effect "An item with the same key has already been added. Key: -10. I don't understand how to prevent this from happening. I do understand what the problem is but not why and how to fix.

First I have a test that looks something like:

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

You can see that this is calling a controller service class passing in the In-memory database that is being generated. The code that this class looks something like this.

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

So you can see it is simply adding a couple items to each of the DbSets after checking that it hasn't already been added. Now if I run this test it will work all day long without any issues at this point.

The problem comes into play when I add the second test, something like this

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

You can see that this test is very similar to the previous one. Doing the exact same thing creating the controller service passing in a new instance of the db context that is built in the generate method.

Here is where the error arises. I'm assuming that the problem is that somehow the context is being generated as a static (even though I'm generating a separate instance each time). And since the tests are being run in parallel it is adding the same items with the same key causing the error.

I have tried removing everything that was static in the GenerateTestData class (class, methods, etc) and using instance variables, but that made no difference.

What am I missing here. I want to generate a separate in memory database for each test, so that there is no dependencies between them.

Aucun commentaire:

Enregistrer un commentaire