$30 off During Our Annual Pro Sale. View Details »

Автотесты. Как пишем их на C#

Автотесты. Как пишем их на C#

Видео доклада: https://www.youtube.com/watch?v=YTnZ8WzC3IE

Бындюсофт

June 14, 2021
Tweet

More Decks by Бындюсофт

Other Decks in Technology

Transcript

  1. Именование Тестовые классы {тестируемый сервис}Tests, пример: CalculatorServiceTests • Легко найти

    тесты на нужный сервис просто используя поиск по имени • CalculationServiceTests\AddTests можно, но надо понять почему возникла необходимость
  2. Именование Тестовые методы {метод}_{сценарий или входное состояние}_{ожидаемое поведение}, примеры: Add_SingleNumber_ReturnsSameNumber

    ExportToFactory_FileExtensionIsZip_ThrowException • Легко найти все тесты на нужный метод • Даже моей бабушке понятно, почему и что происходит • По названиям методов можно быстро погрузиться в домен
  3. Разметка теста Размечаем тесты на Arrange, Act, Assert (добавляем комментарии)

    • Arrange - устанавливаем входное состояние • Act - вызываем метод, который тестируем • Assert - проверяем выходные данные или ожидаемое поведение Структура теста становится более явной и понятной.
  4. Шаблоны кода Для создания тестов используем шаблоны кода (xfact и

    xtheory) • Позволяет не отходить от конвенций • Позволяет экономить время
  5. Логика в тестах Старайтесь избегать написания новой логики в тестах.

    • новая логика - новые возможные баги • неразбериха, где в итоге баг
  6. Приватные методы Приватные методы тестируйте через публичные методы. Нельзя делать

    приватные методы публичными только потому, что мы хотим протестировать их.
  7. Коротыши против Удавов Максимально короткий тест • на его изучение

    уходит минимум времени • для его понимания в голове нужно держать минимум контекста
  8. Коротыши против Удавов Должно проверяться минимальное необходимое количество Asserts, в

    идеале - один • одна проверка - одна причина для падения • тесты более устойчивы к рефакторингу Если вам надо сделать несколько проверок, то сделайте несколько тестов с единственной проверкой!
  9. Выставление состояния Использовать генераторы объектов и сетапы • общую часть

    выносим в сетапы • для создания сущностей использовать генераторы, которые вызываем в коде теста
  10. Покрытие кода Покрытие кода минимум 90%, проверяем покрытие локально (dotCover,

    coverlet) для моментальной обратной связи, в дополнение к проверке на CI • Не нужно дергать и ждать CI • Видно какие места, которые не покрыты и требуют тестов • Можно отдельно смотреть покрытие отдельных тестов, тестовых сессий
  11. Что подразумеваем под важными для тестирования деталями? Есть метод изменения

    таблиц (добавление / удаление / изменение названия полей, изменение типа данных в поле, уникальности). В ходе разработки из него вынесли во вспомогательный класс метод для получения промежуточных данных (массивы данных о том, что и как менять), являвшихся деталями реализации. Стала ли эта несущественная для тестирования часть существенной?
  12. Мнение: Даже если некоторые части системы полностью являются особенностями реализации,

    в некоторых случаях важно тестировать правильность их работы (если они были вынесены в отдельную зависимость, и в них содержится много логики).
  13. Мнение: Не стоит тестировать поведение зависимостей, результат работы которых должен

    использоваться далее в SUT (оно автоматически проверяется при проверке результата), а также неважные детали поведения (например, порядок вызова, если важно только то, что методы должны быть вызваны). Все важные детали поведения стоит покрывать тестами (например, проверка того, что SUT вызывает метод зависимости для всех элементов коллекции).
  14. Мнение: При TDD подходе мы можем занести почти одновременно логические

    ошибки как в тест, так и в тестируемый код. Вероятность этого можно уменьшить программируя в паре или при наличии качественного code review. Как мне кажется, основная польза TDD не в механическом исполнении ритуалов, а в том, что при данном подходе начинает работать критическое мышление: перед тем, как написать тест (без готового кода), приходится отвечать на вопросы о том, что именно мы хотим протестировать, является ли сценарий важным и т. д.
  15. Мнение: Плюсы Strict и It.Is: • очень быстро отлавливается неправильное

    поведение SUT / некорректность теста (если нет сетапа метода, или вызов с другими аргументами - сразу же увидим исключение). Минусы: • сетапы могут стать весьма громоздкими и непонятными с первого взгляда.
  16. [Moq] когда стоит выносить сетапы в хэлпер-классы, а когда нет?

    Примеры: Метод расширения для сетапа: someMock.SetupLogIn(login, password).Returns(loginResult); Обычный сетап: someMock.Setup( m => m.LogIn( It.Is<string>(login_ => login_ == login), It.Is<string>(password_ => password_ == password))) .Returns(() => loginResult);
  17. Мнение: Первый вариант является гораздо более компактным. Второй же позволяет

    изменять поведение изменением переменных благодаря тому, что используются выражения, а не просто переменные: loginResult = LoginResult.Error;
  18. Для тестирования порядка вызовов: someMock .Setup(m => m.SomeMethod(...)) .Callback(() =>

    {if (progress > 2) throw ...; progress = 3;})... Для проверки, что метод был вызван для всех ожидаемых параметров: someMock .Setup(m => m.SomeMethod( It.Is<SomeType>(value => expectedCollection.Contains(value)))) .Callback<SomeType>((value) => { expectedCollection.Remove(value);})...