我一直试图找到一个好的解决方案,但没有运气,所以要么我没有搜索正确的关键字,要么我们从一开始就做错了,所以问题不应该真的存在。
更新澄清:我希望它作为一个单元测试而不是作为一个集成测试工作,所以我不希望它进入数据库,但我想模拟当 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
,它正在分配实体。当SaveChanges()
在上下文中使用实体框架方法将其持久化时,它将关联实体并且 ID 将关联。但是,在我上面的示例中,不会应用实体框架的逻辑。我要说的是代码一旦SaveChanges()
被调用就可以工作,但是单元测试会失败。
在这个简单的示例中,您可能会立即知道测试失败的原因,因为您刚刚在代码之前编写了测试并且可以轻松地修复它。但是,对于更复杂的操作以及未来可能会改变实体关联方式的操作,这将破坏测试但可能不会破坏功能,如何最好地进行单元测试?
我的想法是:
- 服务层应该不知道持久层——我们应该在单元测试中模拟数据上下文来模拟它的工作方式吗?是否有一种简单的方法可以自动绑定关联(即如果使用则分配给正确的实体,
Id
或者如果使用实体则分配正确Id
的实体)? - 还是应该以稍微不同的方式构建测试?
我继承的当前项目中存在的测试与我上面的示例一样工作,但它让我觉得方法有问题,而且我还没有设法找到解决可能常见问题的简单解决方案。我相信应该模拟数据上下文,但这似乎需要将大量代码添加到模拟中以动态创建关联 - 这肯定已经解决了吗?
更新:这些是迄今为止我找到的最接近的答案,但它们并不是我所追求的。我不想这样测试 EF,我只是想知道测试访问存储库的服务方法的最佳实践是什么(直接或通过共享相同上下文的其他存储库的导航属性)。
Entity Framework 4.1 的假 DbContext 进行测试
到目前为止的结论:使用单元测试是不可能的,只有使用真实数据库的集成测试才有可能。您可以接近并可能编写一些代码来动态关联导航属性,但是您的模拟数据上下文永远不会完全复制真实的上下文。如果有任何解决方案使我能够自动关联导航属性,这将使我的单元测试更好,我会很高兴,如果不是完美的话(成功的单元测试的性质无论如何都不能保证功能)ADO.NET模拟上下文生成器很接近,但似乎我必须拥有每个实体的模拟版本,如果在我的实现中使用部分类将功能添加到它们中,这对我不起作用。