NUnit: выполнение нескольких утверждений в одном тесте

Меня попросили написать приложение для тестирования, которое должно протестировать новую хранимую процедуру для нескольких строк в базе данных, по сути, я хочу сделать что-то вроде этого:

[Test]
public void TestSelect()
{
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        Assert.AreEqual(old.Rows[0]["column"],ne_.Rows[0]["column"]);
    }
}

Когда я запускаю этот тест, если одна строка не соответствует другой, весь тест не проходит; вместо этого я хотел бы подсчитать, сколько раз утверждение было принято и сколько раз оно терпело неудачу. Есть ли способ сделать это с помощью NUnit?

Я понимаю, что NUnit может быть излишним, и без него это простая задача ... Я просто хотел изучить его. ;)

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
0
4 984
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

Ну, вы можете объявить счетчик, а затем подтвердить значение счетчика, чтобы определить годен / не годен

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

Я не понимаю, зачем вам нужны все утверждения assert в одном тесте.

Я хочу заявить, что хранимая процедура работает для каждой строки в базе данных.

mmattax 03.10.2008 20:03

Я бы посчитал количество строк, которые не совпадают, а затем написал бы утверждение, которое сравнит это число с 0 и вернет количество несовпадающих строк в сообщении.

вы также можете использовать для этого Assert.Greater.

P.S. В принципе, вы должны пытаться делать одно утверждение для каждого модульного теста. В этом суть.

Похоже, вы просто ошибаетесь. Если вы хотите проверить все значения, а затем подтвердить, что ошибок нет (или показать количество ошибок), попробуйте следующее:

[Test]
public void TestSelect()
{
    int errors = 0;
    foreach(id in ids)
    {
        DataTable old = Database.call("old_stored_proc",id);
        DataTable new_ = Database.call("new_stored_proc",id);

        if (old.Rows[0]["column"] != new_.Rows[0]["column"])
        {
            errors++;
        }            
    }

    Assert.AreEqual(0, errors, "There were " + errors + " errors.");
}
Ответ принят как подходящий

1) Если идентификаторы постоянны и не просматриваются во время выполнения теста, создайте отдельное приспособление для модульного теста для каждого идентификатора. Таким образом вы будете знать, какие идентификаторы на самом деле не работают. См. Здесь описание проблем с тестами на основе данных:
http://googletesting.blogspot.com/2008/09/tott-data-driven-traps.html

2) Если вам нужно динамически искать идентификатор, что делает невозможным создание фикстуры для каждого идентификатора, используйте предложение akmad с одним изменением. Сохраните список идентификаторов, значения которых не равны, и добавьте этот список в сообщение об ошибке. Будет чрезвычайно сложно диагностировать неудачный тест, в котором указывается только количество ошибок, поскольку вы не будете знать, какой идентификатор вызывает ошибки.

3) Я не знаю, насколько сложно это было бы сделать в NUnit, но в PyUnit, когда нам нужно запускать тесты на динамически сгенерированных данных, мы динамически создаем тестовые приспособления и прикрепляем их к классу TestCase, чтобы у нас не получилось тестируйте каждую часть данных, которая не проходит. Хотя я полагаю, что это было бы намного сложнее без динамических способностей Python.

Спасибо, я действительно искал ваш номер 3 ... но, как вы и сказали ... это .net :(

mmattax 04.10.2008 01:04

Исходя из поставленной вами цели, весь тест должен завершится ошибкой, если одна строка не соответствует другой. Подсчет количества успешных или неудачных попыток утверждения дает меньше информации, чем сравнение ожидаемого результата с результатом, который вы получили на самом деле.

Я знаю, что речь идет именно о NUnit, но, что интересно, Галлио / MbUnit имеет функцию, которая позволяет запускать и перехватывать сразу несколько утверждений.

[Test]
public void MultipleTest()
{
    Assert.Multiple(() =>
    {
       Assert.IsTrue(blabla);
       Assert.AreEqual(pik, pok);
       // etc.
    }
}

Assert.Multiple перехватывает все ошибочных утверждений и сообщает о них в конце теста.

У меня недавно была такая же проблема. Я объединил идею подсчета ошибок с упоминанием Янном Тревином Assert.Multiple в метод расширения для IEnumberable, который позволяет мне делать такие вещи, как:

[Test]
public void TestEvenNumbers()
{
    int[] numbers = new int[] { 2, 4, 12, 22, 13, 42 };
    numbers.AssertAll((num) => Assert.That((num % 2) == 0, "{0} is an odd number", num));
}

Результатом является вывод NUnit:

TestEvenNumbers:
  5 of 6 tests passed; 0 inconclusive
FAILED: 13:   13 is an odd number
  Expected: True
  But was:  False

  Expected: 6
  But was:  5

И решение проблемы OP было бы:

[Test]
public void TestSelect()
{
    ids.AssertAll(CheckStoredProcedures);
}

private void CheckStoredProcedures(Id id)
{
    DataTable old = Database.call("old_stored_proc",id);
    DataTable new_ = Database.call("new_stored_proc",id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

Вот метод расширения (обратите внимание, что я использовал «Все» вместо «Несколько» для согласованности с терминологией Linq):

using System;
using System.Text;
using System.Collections.Generic;
using NUnit.Framework;

public static class NUnitExtensions
{
    public static void AssertAll<T>(this IEnumerable<T> objects, Action<T> test)
    {
        int total = 0;
        int passed = 0;
        int failed = 0;
        int inconclusive = 0;
        var sb = new StringBuilder();
        foreach (var obj in objects)
        {
            total++;
            try
            {
                test(obj);
                passed++;
            }
            catch (InconclusiveException assertion)
            {
                inconclusive++;
                string message = string.Format("INCONCLUSIVE: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
            catch (AssertionException assertion)
            {
                failed++;
                string message = string.Format("FAILED: {0}: {1}", obj.ToString(), assertion.Message);
                Console.WriteLine(message);
                sb.AppendLine(message);
            }
        }

        if (passed != total)
        {
            string details = sb.ToString();
            string message = string.Format("{0} of {1} tests passed; {2} inconclusive\n{3}", passed, total, inconclusive, details);
            if (failed == 0)
            {
                Assert.Inconclusive(message);
            }
            else
            {
                Assert.AreEqual(total, passed, message);
            }
        }
    }
}

Вы можете использовать Атрибут [TestCase()], если это простой жестко закодированный список идентификаторов.

[Test]
[TestCase(1234)]
[TestCase(5678)]
[TestCase(7654)]
public void TestSelect(int id)
{
    DataTable old = Database.call("old_stored_proc", id);
    DataTable new_ = Database.call("new_stored_proc", id);

    Assert.AreEqual(old.Rows[0]["column"], new_.Rows[0]["column"]);
}

Это сгенерирует три отдельных теста для каждого идентификатора, и независимо от того, какой запускающий тест nunit вы используете, будет отображаться количество успешных / неудачных тестов.

Если необходимо создать динамический список идентификаторов, рекомендуется использовать Атрибут [TestCaseSource()].

Другие вопросы по теме