TDD в разработке мобильных устройств — часть 3
- Модульное тестирование платформо-зависимого кода в мобильной разработке.
- Portable IoC (Portable.TinyIoC) для мобильной разработки
- Кроссплатформенное модульное тестирование — в процессе.
Это третий пост в моей серии TDD для мобильной разработки. В этом посте показано, как мы можем провести тестовую разработку для мобильных устройств. Мы рассмотрим варианты запуска наших тестов из нашей среды IDE и найдем подходящего для наших разработчиков среды выполнения тестов без необходимости запуска эмулятора или развертывания на устройстве каждый раз, когда мы хотим запустить тесты.
В предыдущем посте я показал, как использовать NUnitLite для написания модульных / интеграционных тестов на Android и iOS. В этом посте показано, как вы можете написать свои модульные тесты с платформой NUnit и запустить их из вашей IDE.
Проблемы с NUnitLite
NUnitLite не имеет тестового бегуна, который мог бы использоваться вне мобильной ОС. Это относится как к Android, так и к iOS. Вот почему каждый раз, когда нам нужно запустить тесты, мы должны развертываться на реальном устройстве или в симуляторе / эмуляторе для запуска тестов.
Теперь это может быть хорошо и необходимо для некоторой логики, специфичной для платформы. Однако в большинстве случаев нам не нужно тестировать код на конкретной платформе. Возьмите пример, который мы имели в предыдущем посте,
public int GetTotal(int first, int second) { return first + second; }
Этот код является простым кодом C #, который может быть размещен за пределами кода, специфичного для платформы, и может использоваться на нескольких платформах, а затем может быть удобно протестирован с использованием NUnit.
Портативная библиотека классов (PCL)
Это подводит нас к использованию PCL (Portable Class Libraries). Прелесть использования PCL заключается не только в совместном использовании кода на нескольких платформах, но и в том, что мы также можем тестировать наш код с использованием полных сред, таких как NUnit или Microsoft Test (хотя я бы действительно придерживался NUnit ).
Имейте в виду, что PCL развиваются, и каждый день появляется довольно мало пакетов для PCL.
Некоторые разработчики могут утверждать, что это проблема, а некоторые — писать свой код в PCL, поскольку он добавляет ограничения и позволяет использовать только подмножество .net, которое поддерживается на всех настроенных платформах.
Это может быть правдой, но вы можете обойти это тремя способами:
1- Поддерживайте только те платформы, которые вам действительно нужны.
Обычно я использую профиль PCL 78 или 158. Это дает мне две основные платформы, на которых я работаю на Android и iOS, а также некоторые более поздние версии Windows phone (8.1) и Silver light. Вам не нужно использовать профили, которые пытаются поддерживать более старые версии, и у вас будет меньше ограничений при использовании этого подхода.
2- Используйте пакеты Nuget.
Установка пакетов Nuget — отличный способ использовать PCL. Всякий раз, когда я пытаюсь сделать что-то, что не поддерживается в подмножестве .NET, я просматриваю магазин Nuget и большую часть времени обнаруживаю, что кто-то уже разработал пакет, который я мог бы просто использовать напрямую. Еще одна приятная вещь о пакетах Nuget, Nuget поддерживает распространение библиотек на несколько платформ. Это означает, что иногда вы получаете пакет, который может поддерживать Android и iOS. В этом случае вы найдете две отдельные папки в / lib (внутри пакета Nuget) по одной папке для каждой платформы (Android, iOS). В некоторых других случаях Nuget может предоставить вам переносимую библиотеку, в которой вы можете получить папки (в каталоге / lib), такие как portable-win81 + net54 + и т. Д. Это означает, что библиотеки dll внутри этой папки можно использовать и ссылаться из профилей такого типа ( Платформы).Это хорошая новость, потому что вы можете просто использовать код, не беспокоясь о том, чтобы что-то изменить. Примеры таких пакетов:
а. SQLite.NET-PCL
б. PCLWebUtility
с. Microsoft.Bcl
д. Microsfot.Bcl.Build
е. Microsoft.Bcl.Async
е. Newtonsoft.Json
3. Абстрагируйте логику, специфичную для вашей платформы, и используйте реализацию, специфичную для платформы.
Иногда ваша логика должна иметь версию для конкретной платформы, скажем, вы делаете что-то с анимацией или криптографией, где вам нужно использовать библиотеки для конкретной платформы.
Лучший способ добиться этого — создать абстракцию, вставленную в библиотеки / классы, которые зависят от этих (специфичных для платформы) компонентов. Это означает, что ваши классы / библиотеки не зависят от кода платформы. Это зависит только от абстракции. Во время выполнения вы можете внедрить специфичную для вашей платформы реализацию через любой контейнер IoC или даже вручную. У меня есть полный пост по IoC в кросс-платформенном здесь . Также стоит взглянуть на реализацию SQLite.NET-PCL, так как она следует именно этому подходу.
MVVM
MVVM — это отличный подход для разработки программного обеспечения, поскольку он гарантирует, что ваша бизнес-логика не будет связана ни с одним уровнем представления / компонентом.
Существует даже MVVMCross, который позволяет создавать приложения кросс-платформенным способом. Тем не менее, я не предпочитаю использовать MVVMCross, потому что он добавляет гораздо больше сложности, чем мне нужно, и в случае, если мне нужно что-то разрабатывать и изменять вне фреймворка, мне нужно будет вложить большие средства в изучение и создание обходных путей. Поэтому я просто придерживаюсь своих моделей ViewModels .
Это означает, что я использую преимущества шаблона MVVM, поскольку мои ViewModels содержат весь мой код бизнес-логики и внедряют эти модели представления в мои контроллеры / докладчики.
ViewModels также может иметь другие сервисы, фабрики, репозитории, внедренные в них (используя контейнер IoC или вручную), и таким образом наш код является кроссплатформенным и очень тестируемым.
public class CalculatorViewModel : ViewModelBase { public int GetTotal(int first, int second) { return first + second; } } //iOS Controller public class CalculatorController : UIViewController { private readonly CalculatorViewModel _viewModel; public CalculatorController (CalculatorViewModel viewModel) { _viewModel = viewModel; } } //android Controller public class CalculatorController : Fragment { private readonly CalculatorViewModel _viewModel; public CalculatorController (CalculatorViewModel viewModel) { _viewModel = viewModel; } }
Письменные тесты
Как вы можете видеть сверху, наша логика теперь находится во ViewModel, и все это можно тестировать независимо от платформы. Это также облегчает нам использование любых тестовых заданий и тестов. Это включает в себя NUnit или Microsoft Test. Это становится еще лучше, мы могли бы даже иметь наши тестовые библиотеки для .NET 4.0 или 4.5, что означает, что мы могли бы использовать все преимущества .NET при написании наших тестов. Это включает в себя использование FakeItEasy и RhinoMock .
Выполнение тестов
Теперь, когда у нас есть все эти отличные настройки, мы можем посмотреть на запуск наших тестов. Для использования Microsoft Test это происходит из коробки, поэтому не нужно устанавливать ничего лишнего. Если вы предпочитаете использовать NUnit, как я, то вы можете установить последнюю версию NUnit (включая адаптер и бегун). Тем не менее, есть даже лучший способ, вы можете просто установить адаптер NUnit (с Runner) из магазина Nuget. Это сделает адаптер и бегунок NUnit частью вашего решения, и вам потребуется установить инфраструктуру на всех компьютерах разработчиков и на сервере сборки (как мы увидим в настройке Continuous Integration Server позже).
Чтобы начать писать тест, вы можете создать библиотеку классов для .NET 4.0 или .NET 4.5, установить пакет NUnit Adapter Nuget и начать писать тесты, как показано ниже:
Выводы
В заключение я продемонстрировал в последних трех постах (1, 2 и 3), как разрабатывать мобильные тесты. Я надеюсь, что это побудит вас начать смотреть на улучшение качества вашего кода и использовать некоторые тактики, о которых мы говорили здесь. Если у вас есть какие-либо комментарии и вопросы, я хотел бы услышать их, так что свяжитесь с нами.
TDD в разработке мобильных устройств — часть 3