-3

参考这篇文章IRepository - Entity implementation我仍然有些怀疑。我的实体没有实现任何主键,也没有任何关于检测某些并发异常的属性。

但是,这是我会坚持的行为。当我测试我的应用程序时,例如通过“内存存储库”,我永远不会得到任何“ConcurrencyException”,也不会出现重复键异常。此外,如果没有主键实现,我将无法执行任何 Edit(T item) 方法,因为我无法检索要编辑的实体。

我是否应该实现一些接口,如“IEntityKey”、“IEntityConcurrency”,以获得真正的解耦和可测试的代码?

4

1 回答 1

0

请注意不要尝试测试存储库的内存实现。那没有价值,也不是测试的目的。您通常要测试的是使用存储库的代码,例如服务和业务逻辑代码、控制器操作等。

也就是说,您不必在所有测试中都使用一个模拟存储库。对于不同的测试用例,拥有不同的测试存储库(甚至只是存储库的片段)通常是有意义的。

例如,如果您觉得需要在并发异常的情况下测试应用程序代码的行为,只需编写一个模拟存储库方法,如下所示:

public void Update(T entity)
{
    throw new DbConcurrencyException();
}

同样,您无法测试当涉及对同一数据库执行操作的多个线程、进程或用户时可能发生重复键异常的所有情况。要在出现此类异常时测试应用程序的行为,只需显式抛出它即可。

如果您想测试应用程序中的插入链是否仅使用唯一键,那么可以,这样的接口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);
}

从存储库中为单元测试返回数据通常属于测试的“排列”部分。它说:如果我从存储库返回一个实体并调用这个或那个方法(“Act”),我希望得到以下结果(“Assert”)。您检索实体的方式不属于您的测试对象。您可以new在测试存储库的Find方法中创建一个实体,并且为此使用“主键”并不重要。如果您想模拟失败的检索,只需null从您的测试存储库中返回。

无论您多么努力,您都无法编写与实体框架完全相同的内存模拟实现,并且数据库将在生产环境中运行。这是基础架构代码,只有使用真正的 EF 提供程序和真正的数据库系统的集成测试才能完全覆盖。

您甚至不能相信您对任何 LINQ 查询的测试——无论它们是使用主键还是实体的任何其他属性——因为它们可能在内存中工作(LINQ-to-Objects),但在使用实体框架(LINQ -to-Entities),它们是否失败甚至可能取决于 EF 提供程序和您的数据库系统。

这是一个非常详细的答案和许多关于您在尝试测试实体框架查询时遇到的问题的示例。

于 2013-04-29T19:42:26.520 回答