gpt4 book ai didi

c# - 如何根据 XUnit 测试隔离 EF InMemory 数据库

转载 作者:IT王子 更新时间:2023-10-29 04:24:12 25 4
gpt4 key购买 nike

我正在尝试使用 InMemory EF7 数据库进行我的 xunit 存储库测试。

但我的问题是,当我尝试处置创建的上下文时,内存中的数据库仍然存在。这意味着一个测试涉及另一个。

我读过这篇文章Unit Testing Entity Framework 7 with the In Memory Data Store并且我尝试在我的 TestClass 的构造函数中设置上下文。但这种方法行不通。当我单独运行测试时,一切正常,但我的第一个测试方法将一些东西添加到数据库中,第二个测试方法从以前的测试方法中的脏数据库开始。我尝试将 IDispose 添加到测试类中,但方法 DatabaseContext 和 DB 仍然存在于内存中。我做错了什么我错过了什么吗?

我的代码如下:

using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xunit;

namespace Fabric.Tests.Repositories
{
/// <summary>
/// Test for TaskRepository
/// </summary>
public class TaskRepositoryTests:IDisposable
{

private readonly DatabaseContext contextMemory;

/// <summary>
/// Constructor
/// </summary>
public TaskRepositoryTests()
{
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
optionsBuilder.UseInMemoryDatabase();
contextMemory = new DatabaseContext(optionsBuilder.Options);

}

/// <summary>
/// Dispose DB
/// </summary>
public void Dispose()
{
//this has no effect
if (contextMemory != null)
{
contextMemory.Dispose();
}
}


/// <summary>
/// Positive Test for ListByAssigneeId method
/// </summary>
/// <returns></returns>
[Fact]
public async Task TasksRepositoryListByAssigneeId()
{
// Arrange
var assigneeId = Guid.NewGuid();
var taskList = new List<TaskItem>();


//AssigneeId != assigneeId
taskList.Add(new TaskItem()
{
AssigneeId = Guid.NewGuid(),
CreatorId = Guid.NewGuid(),
Description = "Descr 2",
Done = false,
Id = Guid.NewGuid(),
Location = "Some location 2",
Title = "Some title 2"
});

taskList.Add(new TaskItem()
{
AssigneeId = assigneeId,
CreatorId = Guid.NewGuid(),
Description = "Descr",
Done = false,
Id = Guid.NewGuid(),
Location = "Some location",
Title = "Some title"
});

taskList.Add(new TaskItem()
{
AssigneeId = assigneeId,
CreatorId = Guid.NewGuid(),
Description = "Descr 2",
Done = false,
Id = Guid.NewGuid(),
Location = "Some location 2",
Title = "Some title 2"
});

//AssigneeId != assigneeId
taskList.Add(new TaskItem()
{
AssigneeId = Guid.NewGuid(),
CreatorId = Guid.NewGuid(),
Description = "Descr 2",
Done = false,
Id = Guid.NewGuid(),
Location = "Some location 2",
Title = "Some title 2"
});


//set up inmemory DB
contextMemory.TaskItems.AddRange(taskList);

//save context
contextMemory.SaveChanges();

// Act
var repository = new TaskRepository(contextMemory);
var result = await repository.ListByAssigneeIdAsync(assigneeId);

// Assert
Assert.NotNull(result.Count());

foreach (var td in result)
{
Assert.Equal(assigneeId, td.AssigneeId);
}

}

/// <summary>
/// test for Add method
/// (Skip = "not able to clear DB context yet")
/// </summary>
/// <returns></returns>
[Fact]
public async Task TasksRepositoryAdd()
{
var item = new TaskData()
{
AssigneeId = Guid.NewGuid(),
CreatorId = Guid.NewGuid(),
Description = "Descr",
Done = false,
Location = "Location",
Title = "Title"
};


// Act
var repository = new TaskRepository(contextMemory);
var result = await repository.Add(item);

// Assert
Assert.Equal(1, contextMemory.TaskItems.Count());
Assert.NotNull(result.Id);

var dbRes = contextMemory.TaskItems.Where(s => s.Id == result.Id).SingleOrDefault();
Assert.NotNull(dbRes);
Assert.Equal(result.Id, dbRes.Id);
}


}
}

我正在使用:

"Microsoft.EntityFrameworkCore.InMemory": "1.0.0"

"Microsoft.EntityFrameworkCore": "1.0.0"

"xunit": "2.2.0-beta2-build3300"

最佳答案

来自documentation ,

Typically, EF creates a single IServiceProvider for all contexts of a given type in an AppDomain - meaning all context instances share the same InMemory database instance. By allowing one to be passed in, you can control the scope of the InMemory database.

与其让测试类成为一次性的并尝试以这种方式处理数据上下文,不如为每个测试创建一个新的:

private static DbContextOptions<BloggingContext> 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<DatabaseContext>();
builder.UseInMemoryDatabase()
.UseInternalServiceProvider(serviceProvider);

return builder.Options;
}

然后,在每个测试中,使用此方法新建一个数据上下文:

using (var context = new DatabaseContext(CreateNewContextOptions()))
{
// Do all of your data access and assertions in here
}

这种方法应该为每个测试提供一个非常干净的内存数据库。

关于c# - 如何根据 XUnit 测试隔离 EF InMemory 数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38890269/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com