Как написать тестовый код в Swift

Итак, этот вопрос все начался, когда я начал выполнять модульное тестирование для простой 2 строки postNotification и addObserver. Из этого аналогичного вопроса здесь вы можете видеть, что для проверки его необходимо добавить ~ 20 строк & часть от общего способа написав свой код.

Перед этой проблемой я впервые понял разницу между Unit Testing и TDD. Тестирование модулей легко, если ваш код можно проверить, т.е. Если вы следите за мышлением TDD. Затем меня привели к тому, как я могу написать тестовый код, который я не нашел много рекомендаций, каждый учебник просто перескакивает на запись unit test. Apple documentation не имеет для этого ничего.

Моя первоначальная мысль заключалась в том, что мне нужно стремиться к "функциональному программированию" и писать свои функции в чистой функции. Но опять же это очень трудоемко и может потребовать много рефакторинга в существующих кодах или даже для новых проектов много добавленных строк, и я даже не уверен, что это правильный подход. Существуют ли какие-либо предлагаемые рекомендации или стандарты для простого написания проверяемого кода?

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

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

Я не знаю, как я могу сгладить процесс более простым способом.

Я не прошу написать тестовый код для NSNotificationCenter, я прошу об общих рекомендациях по написанию тестируемого кода.

Ответ 1

Это довольно большой вопрос, и в нем мнения разработчиков колеблются в самых разных направлениях. Также важно отметить, что создание тестируемого кода во многих отношениях не является специфическим вопросом для Swift: многое из того, что позволяет вам писать тестируемый код регулярно и удобно, зависит от вас, следуя некоторым фундаментальным, общеприменимым принципам. Часто методики проектирования, основанные на тестах, помогают вам косвенно, проверяя, что вы следовали методам, которые делают выполнение кода с помощью тестов правдоподобным, а также приносили вам другие преимущества в производительности и надежности для программистов. Так что, к сожалению, написание тестируемого кода - это не вопрос изучения некоторых механических приемов работы с XCode, а скорее доказательство того, что вы разработали и спланировали программы и библиотеки, которые вы пишете, придерживаясь некоторых хороших практик.

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

  1. Создание тестируемого кода часто является побочным эффектом следования принципам разумного объектно-ориентированного проектирования.

    • Вы можете найти чтение о принципах SOLID полезным.
    • Взгляните также на эту демонстрацию на основе Swift каждого из пяти принципов SOLID.
    • Google Code Reviewer Guide (PDF) также является отличным источником информации о типичных проблемах с OOD и о том, как их избежать (также не случайно этот документ, связанный с OOD, имеет подзаголовок "Написание тестируемого кода").
  2. Следование рациональному объектно-ориентированному дизайну часто само по себе является побочным эффектом хороших архитектурных решений более высокого уровня. В основном, думайте заранее и часто о типах, которые вы планируете ввести в граф объектов в программе. Каковы роли и зависимости между ними? Трудно ли встретить или правильно построить какие-либо зависимости в вашем объектном графе при выполнении кода из разных контекстов (например, из кода пользовательского интерфейса или модульного теста)?

    • Есть много литературы по информатике об архитектурных моделях проектирования. "Банда четырех" остается ценной книгой для чтения на эту тему (хотя не все из них применимы к вашей типичной программе Swift).
    • Взгляните на эту демонстрацию шаблонов проектирования Swift, чтобы узнать, сколько общих шаблонов проектирования можно реализовать в Swift.
    • Особенно, если ваш код предназначен для мобильного приложения, вы должны прочитать о VIPER, архитектурном паттерне, ориентированном на мобильное приложение, который возник из типичных архитектурных потребностей приложений iOS.
    • Чтобы связать шаблоны проектирования с перечисленными выше принципами SOLID, принцип "единой ответственности", пожалуй, является одним из принципов, который наиболее ярко нарушается во многих крупных программах Cocoa, что является результатом неправильных архитектурных практик, что также приводит к очень трудным для тестирования кода. На самом деле люди часто в шутку называют MVC, применяемый на практике в Cocoa, как "Massive View Controller".

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

  • Используйте типы значений, когда можете: Swift хорошо подходит для написания программ, которые минимизируют ссылки с автоматическим подсчетом ссылок (указатели). Это повышает производительность, но также увеличивает ваши шансы на написание надежного кода, который сводит к минимуму непредвиденные зависимости и скачки данных, которые могут быть трудно обнаружить при тестировании.
  • Сохраняйте неизменяемость, когда можете: соглашения о синтаксисе и система типов в Swift помогают избежать изменяемого состояния, что, помимо прочего, негативно влияет на тестируемость вашего кода (настройка графов объектов для тестирования может стать сложной, так как будет достигнуто реальное пригодный для использования во всем мире тестовый охват вашего кода, если возможное пространство состояний в вашей программе велико).
  • Apple также предоставила некоторые рекомендации по архитектуре типов значений и неизменности, которые также касаются тестируемости вашего кода.
  • Используйте протоколы, когда можете: чтобы понять почему, прочитайте принцип подстановки Лискова :-) Более серьезно, предпочтение протоколов над конкретными типами помогает вам писать тестируемый код, например, позволяя вам выполнять зависимости в настройках теста с определенными типами тестов. которые подделывают или высмеивают некоторые ресурсы, не относящиеся к вашим тестам.
  • Используйте методы функционального программирования (когда это имеет смысл): часто сочетающие функциональность с функциями помогают вам писать читаемый, гибкий код, который избегает изменяемого состояния. Я рекомендую Functional Swift от Chris Eidhof и других как хорошее руководство по применению функциональных шаблонов в Swift.

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