如何在DELETE SQL语句期间强制数据层抛出异常?

时间:2014-01-16 21:22:56

标签: c# unit-testing

我有一个从表中删除行的方法。我正在为它编写单元测试。其中一个测试用例必须在delete上导致错误条件以测试try / catch块的catch。我不能为我的生活想到如何引起错误。 ADO,EF ......任何事都可以。

由于

2 个答案:

答案 0 :(得分:2)

  

我有一个从表中删除行的方法。我正在写单位   测试它。

除非该方法实际上包含可测试的内容,否则您可能只是花时间来执行框架功能。作为集成测试的一部分,没有任何问题,但它可能无法进行非常好的单元测试。

让我们假设方法中的单元测试。隔离该功能的一种干净方法是将依赖项的模拟注入到被测试的类中。

在这种情况下,听起来依赖是ADO.Net和/或EF。其中一个模拟可以配置为抛出异常。

public class MyClass
{
    private readonly IRepository _repository;

    public MyClass( IRepository repository )
    {
        _repository = repository;
    }

    public void DoSomethingThatMightThrow()
    {
        // some logic that you want to test

        // this might throw
        var obj = _repository.Delete( 123 );

        // some logic that you want to test
    }
}

[TestMethod]
public void ATest()
{
    // uses Moq framework, but any mocking framework should do this

    var repository = new Mock<IRepository>();
    repository.Setup( o => o.Delete( It.IsAny<int>() ) ).Throws( new DataException() );

    var obj = new MyClass( repository );
    obj.DoSomethingThatMightThrow();
}

我目前正在阅读The Art of Unit Testing,其中讨论了如何识别好单位。作者声称测试不必映射到单个方法,但测试应该隔离逻辑单元并且易于重复。单元测试中对数据库的依赖很少是一个好主意(同样数据访问也可以是一个很好的集成测试的一部分)。

答案 1 :(得分:1)

首先:试着像TimMedora所展示的那样嘲笑它。

但是,如果你不能,你可以通过多种方式解决这个问题,但这需要一些时间,代码,而且并不总是可行的,这取决于你的数据库引擎,数据库结构,数据库内容等等。

尝试使用与查询无关的任何方法!数据库引擎通常有大量的额外功能,可能会导致查询错误!

例如:

  • 在数据库
  • 上创建新用户帐户
  • 为该帐户的DELETE添加该帐户的所有典型权限除外
  • 将一个特定测试的设置更改为以该用户身份登录

结果:由于未授予所需权限,因此将尝试删除任何行。

另一个例子:

  • 创建一个虚拟表RowLock(id int)
  • 将该列的约束添加为foreign key,其目标是TestedTable的PrimaryKey
  • 向RowLock表添加一行,ID等于TestedTable中的某一行

结果:现在您可以删除TestedTable中的任何行,但RowLock标记为1的行除外,并且由于FK约束,尝试删除已标记的行将中止。

您甚至可以更改测试的设置以执行额外的更改(添加用户,添加RowLock表等),然后在拆解测试后清除它(删除用户,删除RowLock表等)..但是因为我说,这一切都需要大量的工作。

我不推荐这样的方法,因为它们非常有限(rowlock只是删除/更新,权限只是每个数据库,每个表或每列等)。但它们仍然是一个很好的最后选择,因为它们具有几乎总是可能的优势 - 比如RowLock只需要DB支持已检查的FK约束。