c# - 命中预期异常测试结束后

标签 c# unit-testing exception

我正在测试一个被其他几个存储库类继承的抽象基存储库类的删除方法。 MyTestRepository 继承了基类,因此我可以针对基类的方法运行测试,而不会将我的测试限制为使用具体类。当我运行我的单元测试时,它通过了,但后来我注意到我在测试数据库中有几个 OrderDetail 和 Schedule 对象,它们是由测试生成的(对象在测试初始化​​期间创建)并且没有被删除,而 Order 对象被删除。我添加了一些断点,并注意到一旦 helper 方法结束并且抛出预期的异常,测试就会结束,并且不会发生对 helper 的其他调用。

这是我第一次尝试单元测试。我的方法错了吗? ExpectedException 是否按预期工作并且我滥用了它,还是我应该使用其他工具?我能想到的获得测试的唯一方法是在帮助程序中放置一个 try catch block ,并在我捕获到 DataAccessException 时断言为真。

    [TestMethod]
    [ExpectedException(typeof(DataAccessException))]
    public void NHibernateRepositoryBaseDelete()
    {
        NHibernateRepositoryBaseDeleteHelper<Order, int>(myOrder, myOrder.OrderId);
        NHibernateRepositoryBaseDeleteHelper<OrderDetail, int>(myOrderDetail, myOrderDetail.OrderDetailId);
        NHibernateRepositoryBaseDeleteHelper<Schedule, int>(mySchedule, mySchedule.ScheduleId);
    }

    private static void NHibernateRepositoryBaseDeleteHelper<T, TKey>(T myItem, TKey myItemId)
    {
        MyTestRepository<T, TKey> myRepository = new MyTestRepository<T, TKey>();
        myRepository.Delete(myItem);
        myRepository.CommitChanges();

        myRepository.GetById(myItemId, false);
    }

最佳答案

我通常不使用 ExpectedException 除非我可以在单个语句中抛出异常 - 或者如果其他测试确保前面的语句不会抛出异常。

在这里,您基本上进行了三个测试 - 您正在测试这些删除调用中的每个 是否会抛出异常。 ExpectedException 所做的只是运行该方法并检查它是否抛出了您要求它抛出的异常 - 它不会尝试从抛出异常的地方继续,并期望它再次抛出。

如果您想检查特定代码段(而不是整个方法)是否抛出异常,请使用:

try
{
    OperationThatShouldFail();
    Assert.Fail("Expected exception");
}
catch (DataAccessException)
{
    // Expected (no need for an assertion though)
}

(并且不再有 ExpectedException - 您不再期望测试方法抛出。)

对于三项检查中的每项,您将拥有这些 block 之一。或者(可能更好)只进行三个测试,每个测试都使用 ExpectedException 但只有一行长。作为另一种选择,您可以将 try/catch 放入您的辅助方法中。

您可能还希望在测试结束时断言相关表为空 - 但这取决于您的情况。

编辑:至于何时清理数据库——我通常喜欢在每个测试的开始时清理它,这样如果我只运行一个失败的测试,我可以看到之后的数据库。如果我要在拆解方法中清理它,我会丢失有值(value)的信息(或被迫留在调试器中)。

编辑:ExpectedException 的另一种替代方法(我怀疑现在在许多测试框架中都有)是使用这样的通用方法:

static void ExpectException<T>(Action action) 
    where T : Exception
{
    try
    {
        action();
        Assert.Fail("Expected exception " + typeof(T));
    }
    catch (T)
    {
        // Expected
    }
}

然后,假设您使用的是 C# 3,您可以使用 lambda 表达式从方法中轻松(多次)调用它。例如:

// Method name shortened for simplicity, and I'm assuming that type inference
// will work too.
public void NHibernateRepositoryBaseDelete()
{
    ExpectException<DataAccessException>(() => 
        DeleteHelper(myOrder, myOrder.OrderId));
    ExpectException<DataAccessException>(() => 
       DeleteHelper(myOrderDetail, myOrderDetail.OrderDetailId));
    ExpectException<DataAccessException>(() => 
       DeleteHelper(mySchedule, mySchedule.ScheduleId));
}

关于c# - 命中预期异常测试结束后,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/640302/

相关文章:

c# - 总是遍历业务层到达数据层?

c# - 根据2个条件选择使用linq

delphi - 如何使用 DUnit 测试私有(private)方法?

python - 在 Python 中处理来自 urllib2 和 mechanize 的异常

java - 尝试...最后...没有捕获生成异常

python - 为什么主进程和子进程在主进程异常后不退出?

c# - 使用 7zip sdk 压缩文件,但存档文件不是原始文件,无法使用 unrar 解压缩

c# - 接受多种枚举类型的方法

delphi - Delphi 中除 DUnit 之外的最佳单元测试工具

unit-testing - 如何在没有这么多模拟的情况下编写测试?