Интеграционное тестирование — Fitnesse

Я прочитал интересную статью Стива Сандерсона о тестировании интеграции вашего ASP.NET MVC-приложения. Я никогда не был фанатом того, что Microsoft сделала со средами тестирования — я обычно предпочитаю NUnit MSTest (встроенная среда тестирования Visual Studio) и презентации Microsoft, которые я видел на других инструментах тестирования, которые они обнаружили. скорее… подпункт Несмотря на это, я думаю, это здорово, что они прилагают усилия в этой области.

Я подумал, что стоит взглянуть на новую облегченную платформу автоматизации тестирования. Чтобы сделать это, я сначала собираюсь взглянуть на некоторые из существующих альтернатив и их сравнение, прежде чем опробовать эту новую платформу.

Что такое интеграционное тестирование
Давайте сначала посмотрим на разницу между модульным тестированием и интеграционным тестированием:

Модульное тестирование — это тестирование на самом базовом уровне. Здесь область действия теста — это единственный метод для одного объекта. Хотя нет правила, согласно которому вы не можете тестировать несколько методов или объектов с помощью модульного теста, мы обычно заглушаем или высмеиваем эти зависимости и никогда не затрагиваем базу данных. Модульные тесты также лежат в основе разработки через тестирование (TDD).
Интеграционное тестирование — это тестирование нескольких объектов и слоев. Мы используем реальную базу данных (которую мы обычно настраиваем с помощью тестовых данных через скрипты или резервные копии) и вместе тестируем весь программный стек. Эти тесты обычно хороши для выявления проблем с различными компонентами, которые не работают вместе, как ожидалось.
Для обоих типов тестов доступно несколько платформ. Для модульного тестирования наиболее популярными являются NUnit, xUnit, MSTest и MbUnit. Для тестирования интеграции большинство разработчиков просто используют NUnit (или аналогичную инфраструктуру) для тестирования базы данных или для веб-проектов. Selenium кажется наиболее популярным вариантом. Хотя для написания интеграционных тестов отлично подходит среда модульного тестирования, вы, как правило, в конечном итоге получаете большие тесты, которые могут стать кошмаром для обслуживания. Обычно проблема заключается в проверке больших объемов данных — модульные тесты просто не позволяют визуализировать результаты в удобном для обслуживания виде.

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

Fitnesse
Fitnesse — это интегрированная среда тестирования, реализованная в виде вики с веб-сервером Java. В то время как фреймворк является веб-ориентированным, ваше приложение не обязательно должно быть — вы можете использовать Fitnesse практически во всех типах приложений (включая веб-разновидности).

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

Я собираюсь показать область, где я считаю, что Fitnesse очень полезен — тестирование уровня хранилища. Для тех из вас, кто ранее не использовал шаблон репозитория, вот краткий обзор. Шаблон репозитория стал очень популярным в DDD (Domain Driven Development), где репозиторий используется для доступа к данным, используемым моделью домена. Это звучит очень впечатляюще, но в основном это означает, что у нас есть 2 представления данных, хранящихся в базе данных — модель данных, которая является точным представлением таблиц базы данных и обычно генерируется ORM, например NHibernate или Linq-to-Sql; и модель предметной области, которая является еще одним представлением данных в том виде, в каком мы хотим работать с ними в нашем приложении. Шаблон репозитория обрабатывает отображение между этими двумя, а также обрабатывает все постоянство. Вы можете найти гораздо лучшее объяснение паттерна репозитория в FAQ по NHibernate.

В этом примере у меня есть 2 объекта интереса — клиенты и аккаунты. Между клиентами и учетными записями существует отношение один-ко-многим, и мой репозиторий должен получить это для каждого клиента.

Код для репозитория является очень простой реализацией.

public class ClientRepository
{
    private readonly DataModelContext context = new DataModelContext();

    public IList<Domain.Client> GetClients()
    {
        var clients = from client in context.Clients
                        select new Domain.Client
                                   {
                                       Id = client.Id,
                                       Code = client.Code,
                                       Name = client.Name,
                                       Telephone = client.Telephone,
                                       Fax = client.Fax,
                                       Accounts = GetAccountsFor(client.Id)
                                   };

        return clients.ToList();
    }

    private IList<Domain.Account> GetAccountsFor(int clientId)
    {
        var accounts = from account in context.Accounts
                       where account.ClientId == clientId
                       select new Domain.Account
                       {
                           Id = account.Id,
                           Number = account.Number,
                           Type = account.Type
                       };

        return accounts.ToList();
    }
}

Хорошо, так как мы можем это проверить? Ни один из инструментов тестирования интеграции не может протестировать этот уровень изолированно, хотя все они могут тестировать этот уровень как часть полного стека кода. Мы могли бы использовать среду модульного тестирования, но это приведет к целому ряду утверждений Assert и сделает наши тесты очень трудными для сопровождения. Fitnesse идеально подходит для этого типа сценария, поскольку он позволяет нам писать собственные фиксаторы и выбирать нашу точку входа в стек кода.

Для этого конкретного сценария я собираюсь создать прибор C #, который вызывает ClientRepository и возвращает полученные объекты в Fitnesse. Мне нужно написать 2 фиксатора — один для проверки возвращаемых клиентов и другой для списка счетов, возвращаемых с каждым клиентом. Чтобы сделать это, нам нужно создать 2 фиксатора строки — Fitnesse использует несколько различных типов приборов, но чаще всего мы используем фиксаторы строк и столбцы. Как правило, фиксированные строки используются для проверки извлеченных данных, в то время как фиксированные столбцы используются для выполнения действий.

public class ClientRepositoryClientsFixture : RowFixture
{
    public override object[] Query()
    {
        return new ClientRepository().GetClients().ToArray();
    }

    public override Type GetTargetClass()
    {
        return typeof(Client);
    }
}
public class ClientRepositoryAccountsFixture : RowFixture
{
    public override object[] Query()
    {
        var client = new ClientRepository().GetClients().Single(c => c.Name == Args[0]);

        return client.Accounts.ToArray();
    }

    public override Type GetTargetClass()
    {
        return typeof(Account);
    }
}

Обратите внимание, что во втором приборе я буду передавать в прибор параметр — имя клиента. Итак, теперь мы можем запустить веб-сервер Fitnesse, создать ожидания с помощью интерфейса вики и запустить тест.

Здесь вы можете увидеть ожидания, которые я создал с помощью интерфейса вики. Значения разделены каналом, и нам нужно указать полные имена классов для используемых нами приборов. Создание ожиданий может быть довольно трудоемким, но как только вы закончите, результаты будет намного легче просмотреть, чем целый набор операторов C # Assert (что будет, если мы выполним этот тест с использованием NUnit или аналогичной среды) , Вы также можете создать ожидания в Excel.

Это результат запуска теста. Мои ожидания верны (я ожидаю данных, которые я указал в базе данных), но мой тест не пройден, потому что в моем коде действительно есть ошибка — я не отображаю поле Фамилия в классе репозитория. Довольно аккуратно. После того, как я исправил ошибку и перекомпилировал все это становится зеленым.

Здесь вы также можете увидеть, как я передал параметр в rowfixture — просто добавьте значение после имени прибора, и Fitnesse сделает его доступным в качестве параметра. Теперь, когда мы закончили, мы можем также включить эти тесты как часть нашего процесса сборки.

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

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

преимущества
Возможность тестирования отдельных слоев в изоляции
Легко поддерживать тесты и просматривать результаты тестов
Ожидания можно настроить в Excel
Недостатки
Веб-интерфейс может сделать настройку ожидания трудоемкой
Невозможно явно протестировать веб-интерфейс
В моем следующем блоге я взгляну на Selenium.

Author: admin