【问题标题】:Unit Testing for Linq MethodLinq 方法的单元测试
【发布时间】:2021-11-29 02:32:33
【问题描述】:

我有一个方法,我必须为其编写单元测试。此方法使用数据库上下文从数据库中检索详细信息。

现在我正在考虑如何模拟这个数据库上下文并测试剩余的 LINQ 代码。

同样,我还有其他方法,它们有一些逻辑和一些 LINQ 查询,我也想对它们进行单元测试。

public class OrderService
{
    private DataContext _context;

    public OrderService(DataContext context)
    {
        _context = context;
    }

    public int OrderCount(int orderId)
    {
        var count = _context.Orders.Where(x=>x.orderId==orderId).ToList().Count;
    }
}

我应该如何处理这种情况?

这是开发人员面临的常见情况,但关于此的可用信息不多。任何建议将不胜感激。

【问题讨论】:

  • 您应该模拟代码以从数据库中检索数据。单元测试在真实数据库中不起作用
  • 如果该代码具有许多业务逻辑以及从数据库中检索数据怎么办?
  • 你可以使用内存数据库
  • 另一种方法是在 dbcontext 上创建包装器。无论如何我都会使用内存数据库
  • 似乎是一个有趣的想法,你有任何参考或链接。

标签: c# linq unit-testing nunit moq


【解决方案1】:

我的建议是将您的数据在数据库中的事实与您想要获取数据的方式分开。

换句话说:你的 LINQ 方法应该有 IQueryable<...> 作为输入。不是 DbContext。

除了这将使您的单元测试变得轻而易举之外,它还允许您重用 LINQ 处理来自不同来源的数据,例如不同的数据库、CSV 文件或 XML ,或者可能只是来自字典。

我创建了一个扩展方法。如果你对扩展方法不熟悉,可以考虑阅读Extension Methods Demystified

public static int Count(this IQueryable<Order> orders, int orderId)
{
    return orders.Where(order=>order.orderId==orderId).Count();
}

用法:

int orderId = this.ReadOrderId();
using (var dbContext = new MyOrderContext(...))
{
    return dbContext.Orders.Count(orderId);
}

也许CountByOrderId 是一个更好的名字。

对于您的单元测试,例如测试空订单集合的 CountByOrderId:

int orderId = 4;
var emptyOrderCollection = Enumerable.Empty<Order>();
int orderCount = emptyOrderCollection.CountByOrderId(orderId);
Assert.AreEqual(..., orderCount);

顺便问一下,你有没有注意到我删除了ToList?先创建一个List,然后只使用里面的元素个数,然后就扔掉这个list,有点浪费处理能力。

通用解决方案

如果您想让您的计数方法更加通用,例如还计算具有特定价格的产品或特定出生年份的学生:

public static CountByProperty<TSource, TPropery>(this IQueryable<TSource> source,
    Expression<Func<TSource,TProperty>> propertySelector,
    TProperty value)
{
    return source.Where(s=>propertySelector(s)==value).Count();
}

用法:

return dbContext.Orders.CountByProperty(order => order.OrderId, 4);

或计算价格恰好为 1.00 美元的产品:

return dbContext.Products.CountByProperty(product => product.Price, 1.00);

【讨论】:

  • Where(s=&gt;propertySelector(s)==value) 将不起作用。你可以自己试试。
  • 如果带有propertySelector的方法不起作用,可以考虑使用Expression&lt;Func&lt;TSource,bool&gt;&gt; predicate作为参数。谓词必须类似于 product =&gt; product.Price == 1.00
猜你喜欢
  • 2014-05-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-29
  • 1970-01-01
相关资源
最近更新 更多