繁体   English   中英

Linq to SQL的单元测试实践

[英]Unit Testing practice with Linq to SQL

我试图将精力放在单元测试上,但是遇到了不确定的行为:

“可以备份库存”

基本上,“库存”表被复制到“库存历史”表,并给出备份发生时间的时间戳(“ HistoryDate”)。

这是备份库存的代码:

        DateTime historyDate = DateTime.Now;
        MyDataContext db = new MyDataContext();

        db.GetTable<InventoryHistory>().InsertAllOnSubmit(
            db.GetTable<Inventory>()
                .Select(i => new InventoryHistory
                {
                    ID = i.ID,
                    ItemName = i.ItemName,
                    /* etc, etc, etc */
                    HistoryDate = historyDate

                })
        );

我的问题是:

  1. 应该/可以将这种行为分解为较小的可单元测试的部分吗?

  2. 由于我正在针对专用的测试数据库进行测试,因此我是否应该使用模拟工具并遵循任何“存储库”的抽象工厂模式?

我要问的问题是,这真的是单元测试吗? 单元测试将考虑模拟的Table<TEntity>实例,因为我们不关心实际数据,而是创建项目的机制是正确的。

在上面的代码段中,您似乎在对Linq方法本身进行单元测试,而不是自己编写的任何特定代码。

至于你的最后一个问题,用嘲讽取得了根本性的错误之一就是测试时,嘲讽的假设。 通常,您会嘲笑您要测试的类型所消耗的东西。 例如:

public ICalculatorService
{
  int Add(int a, int b);
}

[Test]
public void CannAdd()
{
  var mock = Mock<ICalculatorService();
  mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>()))
      .Returns(100);

  var service = mock.Object;
  Assert(service.Add(1, 2) == 100); // Incorrect
}

上面的测试是没有意义的,因为我正在测试它完全返回了我所告诉的内容。 我不在这里测试Moq框架,我需要测试我的代码,所以我需要测试使用者:

public class Calculator
{
  private readonly ICalculatorService _service;

  public Calculator(ICalculatorService service)
  {
    _service = service;
  }

  public int Add(int a, int b)
  {
    return _service.Add(a, b);
  }
}

[Test]
public void CannAdd()
{
  var mock = Mock<ICalculatorService();
  mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>()))
      .Returns(100);

  var calculator = new Calculator(mock.Object);
  Assert(calculator.Add(1, 2) == 100); // Correct
}

这更像它(尽管是一个简单的例子)。 我现在正在测试Calculator使用者本身,而不是消耗品。 在您的示例中,即使您正在模拟DataContext以返回Table<TEntity>虚拟实例,您还能获得什么真正的好处?

实际上,您可能会创建一个存储库,例如IInventoryRepository ,并创建该存储库的使用者(可以是域模型,控制器等)。 然后通过测试,您可以模拟该存储库,并测试您的使用者。

对我来说,这似乎是一项相当原子的操作,没有太多机会将其分解。

单元测试不会影响数据库-这是集成测试。 如果您要对此进行良好的单元测试,则可以测试行为-在这种情况下,应按原样备份历史记录。

通过全面披露,我才刚刚开始学习EF和LINQ以及测试它们的最佳方法,因此,您可能会获得有关它们的更多有用信息,因此,这些只是一般的测试答案。

1.除了以下方面,我看不到一种可以进一步细分以进行单元测试隔离的方法:

ID = i.ID,
ItemName = i.ItemName,
/* etc, etc, etc */
HistoryDate = historyDate

被重构为单独的方法以进行单元测试,因为只有LINQ调用是其他代码,MS负责测试。

2.我认为您无法引入接缝以将其与抽象存储库工厂模式隔离,因为您正在调用数据上下文。

我不确定您是否应该伪造此代码(由于您要对其进行测试将是一个模拟的正确方法-您对其进行测试的伪造品,而您未对其进行测试的伪造品是存根 ),但是由于它正在调用在测试服务器中,由于该功能涉及与数据存储的交互,因此您可以使其成为自动集成测试

首先,您描述的方法看起来很简单,但我不确定它是否需要任何单元测试。 但是,如果要分解,可以执行以下操作:

  1. 提取要备份的清单清单的提取方法

    IQueryable GetInventoryForBackup(此DataContext上下文){return context.GetTable(); }

  2. 提取方法将库存转换为库存历史

    IEnumerable ToInventoryHistory(此IEnumerable数据,DateTime historyDate){返回data.Select(i => new InventoryHistroy {ID = i.Id ....}

  3. 提取方法以保存InventoryHistory的顺序

    SaveHistory(IEnumerable data){dataContext.InsertAllOnSubmit(data); dataContext.SubmitChanges(); }

现在您有了看似可行的方法,并且可以轻松编写单元测试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM