После попадания expectedexception тест заканчивается - PullRequest
5 голосов
/ 12 марта 2009

Я тестирую метод delete абстрактного базового класса репозитория, который наследуется несколькими другими классами репозитория. MyTestRepository наследует базу, поэтому я могу запускать тесты с методами базы, не ограничивая мой тест использованием конкретного класса. Когда я запускаю свой модульный тест, он проходит, но потом заметил, что у меня есть несколько объектов OrderDetail и Schedule в тестовой БД, которые были сгенерированы тестом (объекты создаются во время инициализации теста) и не удаляются, а объект Order удаляется. Я добавил несколько точек останова и заметил, что как только завершается вспомогательный метод, и генерируется ожидаемое исключение, тест завершается, и другие вызовы вспомогательного средства никогда не происходят.

Это моя первая попытка модульного тестирования. Мои методологии неверны? ExpectedException работает должным образом, и я неправильно его использую, или есть другой инструмент, который я должен использовать? Единственный способ, которым я могу придумать, чтобы получить мой тест, - это поместить блок try catch в помощник и утверждать true, когда я ловлю свое 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);
    }

Ответы [ 2 ]

11 голосов
/ 12 марта 2009

Обычно я не использую ExpectedException, если только я не могу вызвать исключение в одном операторе или если другие тесты гарантируют, что предыдущие операторы не выдают исключение.

Здесь у вас есть в основном три теста - вы проверяете, что каждый из этих вызовов удаления выдает исключение. Все, что ExpectedException делает, это запускает метод и проверяет, что оно выдает исключение, о котором вы его просили - оно не пытается продолжить с того места, где было сгенерировано исключение, ожидая, что оно будет сгенерировано снова.

Если вы хотите проверить, что исключение выдается определенным фрагментом кода (а не только целым методом), используйте:

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

(И больше не иметь ExpectedException - вы больше не ожидаете, что метод теста сгенерирует.)

У вас будет один из этих блоков для каждого из трех проверок. В качестве альтернативы (и, возможно, лучше) просто иметь три теста, каждый из которых использует ExpectedException, но имеет длину только одну строку. В качестве другой альтернативы, вы можете поместить try/catch в ваш вспомогательный метод.

Вы также можете захотеть получить в конце теста утверждение, что соответствующие таблицы пусты, но это зависит от вашей ситуации.

РЕДАКТИРОВАТЬ: Что касается, когда вы очищаете базу данных - я обычно люблю очищать ее при старте каждого теста, чтобы, если я запускаю только один неудачный тест, я мог видеть состояние базы данных после этого. Если бы я очистил его методом разрыва, я бы потерял ценную информацию (или был бы вынужден остаться в отладчике).

РЕДАКТИРОВАТЬ: Еще одна альтернатива ExpectedException (которая, я подозреваю, сейчас используется во многих тестовых средах) - использовать общий метод, подобный этому:

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

Затем вы можете вызвать его легко (несколько раз) из метода, используя лямбда-выражение для действия, предполагая, что вы используете 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));
}
5 голосов
/ 12 марта 2009

Оберните код модульного теста в блок 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
    }   
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...