参考这篇文章IRepository - Entity implementation我还有一些疑问。 我的实体没有实现任何主键,也没有任何关于属性的东西来检测某些并发异常。
但是,这就是我要保持的行为。当我测试我的应用程序时,例如通过“内存reposiotry”,我永远不会得到任何“ConcurrencyException”,也不会重复键异常。此外,没有primay键实现,我无法执行任何Edit(T item)方法,因为我无法检索要编辑的实体。
我应该实现一些像“IEntityKey”,“IEntityConcurrency”这样的接口,以获得真正的解耦和可测试代码吗?
答案 0 :(得分:0)
请注意,不要尝试测试存储库的内存实现。这没有价值,也不是测试的目的。您通常要测试的是使用存储库的代码,例如服务和业务逻辑代码,控制器操作等。
也就是说,您不必在所有测试中使用一个模拟存储库。对于不同的测试用例,拥有不同的测试存储库 - 甚至只是存储库的片段 - 通常是有意义的。
例如,如果您觉得需要在并发异常的情况下测试应用程序代码的行为,那么只需编写一个这样的模拟存储库方法:
public void Update(T entity)
{
throw new DbConcurrencyException();
}
同样,当涉及多个线程,进程或用户作用于同一数据库时,您无法测试可能发生重复键异常的所有情况。要在出现此类异常的情况下测试应用程序的行为,请将其明确抛出。
如果你想测试你的应用程序中的一个Inserts链是否只使用唯一键那么是,像IEntityWithKey
这样的接口可能会有所帮助(它也可以有一个复合键的两个属性)并使用像:
public void Add(T entity)
{
if (InMemoryListOfT.Any(e => e.Key1 == entity.Key1 && e.Key2 == entity.Key2))
throw new DuplicateKeyException();
InMemoryListOfT.Add(entity);
}
如果在这种可能的情况下只涉及一个特定的实体,比如说Order
,我甚至不会看到以通用的方式做这件事的必要性。对于这个特殊测试,您还可以使用这样的存储库方法,您不需要键接口:
public void Add(T entity)
{
if (entity is Order)
{
var order = entity as Order;
var inMemoryListOfOrder = InMemoryListOfT as List<Order>;
if (inMemoryListOfOrder.Any(o => o.OrderId == order.OrderId))
throw new DuplicateKeyException();
}
InMemoryListOfT.Add(entity);
}
从存储库返回单元测试数据通常属于&#34; Arrange&#34;测试的一部分。它说:如果我从存储库返回一个实体并调用这个或那个方法(&#34; Act&#34;)我希望得到以下结果(&#34; Assert&#34;)。检索实体的方式不是测试对象的一部分。您可以在测试存储库的new
方法中创建一个Find
的实体,如果您使用&#34;主键&#34;则无关紧要。为了这。如果要模拟失败的检索,只需从测试库返回null
。
无论你怎么努力,你都无法编写一个内存模拟实现,其行为与Entity Framework完全相同,数据库将在生产中运行。这是基础架构代码,您只能使用真正的EF提供程序和真实数据库系统进行集成测试。
您甚至无法信任有关任何LINQ查询的测试 - 无论是使用主键还是实体的任何其他属性 - 因为它们可能在内存中工作(LINQ到对象)但在出现异常时失败使用实体框架(LINQ到实体),如果它们失败或者甚至可能依赖于EF提供者和您的数据库系统。
以下是关于您在尝试测试实体框架查询时遇到的问题的a great detailed answer and lots of examples。