400 likes | 629 Views
Модульное тестирование. Виды тестов. Модульные Тестируется функционал ограниченной части кода (минимум – класса) Тесты изолированы от других частей кода (не зависят от изменений в других классах) Интеграционные Тестируется взаимодействие между модулями Системные Тестируется система в целом.
E N D
Виды тестов • Модульные • Тестируется функционал ограниченной части кода (минимум – класса) • Тесты изолированы от других частей кода (не зависят от изменений в других классах) • Интеграционные • Тестируется взаимодействие между модулями • Системные • Тестируется система в целом
Модульные тесты • Определение. МТ – некоторый код (обычно метод), который вызывает другой участок кода (unit of code) с целью проверить некоторую гипотезу. Если гипотеза не подтверждается, тест считается неуспешным (fail). • Unit, как правило, метод или функция • Технически корректное определение мало помогает в написании МТ
Модульные тесты • Если писать МТ неправильно – пользы от них не будет (кроме как набирания опыта в написании правильных) • Необходимо определить признаки «хороших», правильных МТ • Тестовое приложение с одной кнопкой – пример МТ, который писал каждый
Свойства МТ • Полностью автоматизирован и воспроизводим (automated and repeatable) • Простой в реализации • Может использоваться достаточно долго • Любой способен запустить его и увидеть результат • Может быть запущен «одной кнопкой» (не требует конфигурирования) • Должен исполняться быстро (весь пакет тестов не должен выполняться более 1-2 минут)
Недостатки интеграционных тестов • Требуют конфигурирования • Требуют специальных знаний для запуска и конфигурирования (=> не все могут запускать их) • Выполняются дольше (=> не могут выполняться часто) • Тестируют большой кусок системы за один раз (труднее локализовать ошибку и ответственного за исправление)
Требования к хорошему МТ • Trustworthiness (к тесту должно быть доверие) • Переписывать/удалять устаревшие • Не помещать в тест много логики • Тестировать одну вещь за один тест • Хорошее покрытие кода тестами • Maintainability (тест должно быть легко поддерживать) • Не тестируются закрытые методы • МТ должны быть изолированы • Readability (тест должен быть понятным) • Понятные названия (можно на русском) • Тесты документируют код • Осмысленные assert
Пример МТ с использованием NUnit • Тестируемый класс
Пример МТ с использованием NUnit • Методы SetUpи TearDown
Пример МТ с использованием NUnit • Тривиальные тесты
Пример МТ с использованием NUnit • Тривиальные тесты
Зависимости (Dependencies) • Зависимости препятствуют написанию МТ (test-inhibiting design) • Приходится избавляться от прямых зависимостей Предположим, выполнение метода требует чтения конфигурационного файла:
Inversion of Control • Выделяем работу с внешним ресурсом в отдельный класс
Inversion of Control • Выделяем интерфейс
Inversion of Control • Пишем заглушку
Dependency Injection • Dependency Injection (внедрение зависимости) – способ разрешения зависимостей в коде • Получить интерфейс через конструктор и сохранить его в поле класса (constructor injection) • Открыть интерфейс как свойство и устанавливать его перед вызовом метода (property injection) • Получать интерфейс в момент вызова метода: • В виде входного параметра (parameter injection) • С помощью фабрики • С помощью внутреннего метода, работающего в качестве фабрики (local factory method или Extract-and-Override) • Комбинируя эти подходы
Внедрение через конструктор • Слишком много конструкторов и параметров • Не управляем временем жизни объекта • Внедрение через свойство • Может быть нарушение инкапсуляции
Dependency Injection • Использование фабрики • Одна фабрика возвращает настоящий объект в рабочем коде, или fake в тестовом • Используются две фабрики: настоящая и для тестового кода (создаётся фейк для самой фабрики)
Dependency Injection • Extract-and-Override • В тестируемом классе создаём виртуальный метод-фабрику • Наследуемся от класса и перегружаем метод-фабрику, чтобы он возвращал фейк • Тестируем дочерний класс
Dependency Injection • Extract-and-Override для создания заглушек
DI-фреймворки (IoCконтейнеры) • IoCконтейнеры для .NET • Unity Application Block 2.0 • Spring.NET • StructureMap • CastleProject • Seasar • Winter.NET • Ninject
DI-фреймворки (IoCконтейнеры) • Unity Application Block
DI-фреймворки (IoCконтейнеры) • Unity Application Block
Fake-объекты в МТ • Модульное тестирование: • State-Based Testing (a.k.a. State Verification) • Корректность определяется проверкой состояния тестируемого объекта после выполнения метода • Interaction Testing • Корректность определяется тем, как объект взаимодействует с другими объектами во время теста (пример с проверкой системы полива) • В некоторых случаяхтест может быть эквивалентно выражен либо как State-Based тест, либо как Interaction тест
Fake-объекты в МТ • Fake-объекты: • Mocks (моки) • Stubs (заглушки)
Mock-объекты в МТ • Пример ручного создания мока
Mock-объекты в МТ • Пример ручного создания мока
Mock-объекты в МТ • Пример ручного создания мока
Fake-объекты в МТ • Советы • Можно использовать несколько заглушек в одном тесте • Не стоит использовать больше одного мока в одном тесте • Нужно тестировать контракт класса, не пытаться тестировать ожидаемую внутреннюю реализацию
Fake-объекты в МТ • Проблемы с Fake-объектами, созданными вручную • На их написание требуется время • Если в классах-зависимостях много методов, писать моки и заглушки становится трудно • Написанные фейки для одного теста трудно повторно использовать для других
Isolation фреймворки • Существующие .NET Isolation фреймворки(a.k.a. mock-object фреймворки) • FakeItEasy • Microsoft Moles • Moq • NMock • NSubstitute • POCMock • Rhino Mocks • Typemock
Isolation фреймворки Ручное создание мока С помощью Rhino Mocks (стиль record-and-replay)
Isolation фреймворки Ручное создание мока С помощью Rhino Mocks (стиль arrange-act-assert)
Isolation фреймворки Ручное создание мока С помощью Moq
Isolation фреймворки • Ограничения Isolation фреймворков • Фейки можно создавать только для виртуальных нестатических методов (кроме Moles иTypeMock)
Ссылки • Roy Osherove. The Art of Unit Testing