gpt4 book ai didi

c# - 单元测试 : TDD with POCO Objects with navigation properties (relationship fixup)

转载 作者:太空狗 更新时间:2023-10-29 21:17:52 32 4
gpt4 key购买 nike

我一直在努力寻找一个好的解决方案,但没有成功,所以要么我没有搜索正确的关键字,要么我们从一开始就做错了,所以这个问题不应该真的存在.

澄清更新:我希望它作为单元测试而不是集成测试,所以我不希望它访问数据库,但我想模拟关联当 EF 在我的单元测试中坚持更改时进行。

原始问题:

假设您正在测试这样的服务方法:

[Test]
public void AssignAuthorToBook_NewBookNewAuthor_SuccessfullyAssigned()
{
IBookService service = new BookService();

var book = new Book();

var Author = new Author() { Id = 123 };

service.AssignAuthorToBook(book, author);

Assert.AreEqual(book.AuthorId, 123);
}

现在假设此测试失败,因为 AssignAuthorToBook 实际上使用代码 book.Author = author; 工作,所以它没有分配 AuthorId,它正在分配实体。当在上下文中使用 Entity Framework SaveChanges() 方法将其持久化时,它将关联实体,并且 ID 将关联。但是,在我上面的示例中,不会应用 Entity Framework 的逻辑。我的意思是,一旦调用了 SaveChanges(),代码就会工作,但单元测试会失败。

在这个简单的示例中,您可能会立即知道测试失败的原因,因为您刚刚在代码之前编写了测试并且可以轻松修复它。但是,对于更复杂的操作以及 future 可能会改变实体关联方式的操作,这会破坏测试但可能不会破坏功能,如何最好地进行单元测试?

我的想法是:

  • 服务层应该不知道持久层——我们应该在单元测试中模拟数据上下文来模拟它的工作方式吗?有没有一种简单的方法可以自动绑定(bind)关联(即如果使用 Id 则分配给正确的实体,或者如果使用实体则分配正确的 Id ) ?
  • 或者测试的结构应该略有不同吗?

我继承的当前项目中存在的测试与上面的示例一样工作,但令我烦恼的是这种方法有问题,而且我还没有设法找到一个可能常见的简单解决方案问题。我认为应该模拟数据上下文,但这似乎需要将大量代码添加到模拟中以动态创建关联 - 这肯定已经解决了吗?

更新:这些是我迄今为止找到的最接近的答案,但它们并不是我想要的。我不想这样测试 EF,我只是想知道测试访问存储库的服务方法的最佳实践是什么(直接或通过共享相同上下文的其他存储库的导航属性)。

How Do I Mock Entity Framework's Navigational Property Intelligence?

Mocked datacontext and foreign keys/navigation properties

Fake DbContext of Entity Framework 4.1 to Test

Navigation properties not set when using ADO.NET Mocking Context Generator

目前的结论:使用单元测试是不可能的,只有使用真实数据库的集成测试才有可能。您可以接近并可能编写一些代码来动态关联导航属性,但您的模拟数据上下文永远不会完全复制真实上下文。如果有任何解决方案使我能够自动关联导航属性,这将使我的单元测试更好,即使不完美(成功的单元测试的性质并不能以任何方式保证),我会很高兴无论如何功能) ADO.NET Mocking Context Generator接近,但似乎我必须有每个实体的模拟版本,这对我不起作用,以防在我的实现中使用部分类将功能添加到它们。

最佳答案

我认为您期望测试结果暗示使用多个依赖项,可以说不符合单元测试的条件,尤其是因为对 EF 的隐含依赖性。

这里的想法是,如果你承认你的 BookService 依赖于 EF,你应该使用模拟来断言它与它正确交互,不幸的是 EF 似乎不喜欢被模拟,所以我们总是可以把它在存储库下,这是一个如何使用 Moq 编写该测试的示例:

[Test]
public void AssignAuthorToBook_NewBookNewAuthor_CreatesNewBookAndAuthorAndAssociatesThem()
{
var bookRepositoryMock = new Mock<IBookRepository>(MockBehavior.Loose);
IBookService service = new BookService(bookRepositoryMock.Object);
var book = new Book() {Id = 0}
var author = new Author() {Id = 0};

service.AssignAuthorToBook(book, author);

bookRepositoryMock.Verify(repo => repo.AddNewBook(book));
bookRepositoryMock.Verify(repo => repo.AddNewAuthor(author));
bookRepositoryMock.Verfify(repo => repo.AssignAuthorToBook(book, author));
}

要设置的 id 是您将使用集成测试的东西,但我认为您不应该担心 EF 无法设置 Id,我说这个的原因与您不应该担心的相同测试 .net 框架是否执行它应该执行的操作。

我过去写过关于交互测试的文章(我认为在这种情况下这是正确的方法,您正在测试 BookService 和 Repository 之间的交互),希望对您有所帮助:http://blinkingcaret.wordpress.com/2012/11/20/interaction-testing-fakes-mocks-and-stubs/

关于c# - 单元测试 : TDD with POCO Objects with navigation properties (relationship fixup),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18235264/

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