点击expectedexception测试结束后

时间:2009-03-12 20:19:08

标签: c# unit-testing exception

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

这是我第一次尝试进行单元测试。我的方法是错的吗? ExpectedException是否按预期工作,我是在滥用它还是我应该使用另一种工具?我能想到的唯一方法就是在helper中放一个try catch块,当我捕获DataAccessException时断言为true。

    [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);
    }

2 个答案:

答案 0 :(得分:11)

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

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

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

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

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

这三个支票的每个都有其中一个块。或者(可能更好)只有三个测试,每个测试使用ExpectedException但只有一行。作为另一种选择,您可以将try/catch放入辅助方法中。

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

编辑:至于你清理数据库的时候 - 我通常喜欢在每个测试的 start 上清理它,这样如果我只运行一次失败的测试,我就能看到它的状态。数据库之后。如果我要在拆解方法中清理它,我会丢失有价值的信息(或者被迫留在调试器中)。

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

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

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

// 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));
}

答案 1 :(得分:5)

将您的单元测试代码包装在try / finally块中,并在finally部分内清理数据库。

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