Статьи

TDD в разработке мобильных приложений, часть 2: переносимая миниатюрная инверсия контейнера управления

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

TDD в разработке мобильных устройств
1. Модульное тестирование кода для платформы в мобильной разработке
2. Портативный IoC (Portable.TinyIoC) для разработки мобильных приложений
3. Идет межплатформенное модульное тестирование.

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

способность быть свидетелем в суде

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

По сути, ваши классы / библиотеки должны заранее объявить, какие у них зависимости. Недопустимо иметь классы, которые просто создают (используя ключевое слово new или иным образом) другие классы или вызывают статические методы / поля из других объектов. Вы можете спросить почему? и я рад, что ты спросил. Это потому, что такие классы / библиотеки не подлежат тестированию. Вы не можете издеваться / подделывать / изменять их внутреннее поведение. Что еще хуже, некоторые из этих внешних зависимостей или статических классов могут зависеть от платформы или могут требовать определенного контекста среды для возврата определенного вывода, что означает, что такой код будет тестируемым только в нескольких небольших сценариях. Еще хуже то, что использование статических методов дает вам больше головной боли, когда речь идет о безопасности потоков, что само по себе является еще одной темой.

Следовательно, ваш код должен быть достаточно чистым и заранее объявлять свои зависимости, чтобы мы могли протестировать его при разделении других зависимостей. Для этого была введена концепция инверсии контроля ( IoC ). Контейнеры IoC позволяют разработчикам регистрировать зависимости в начале приложения в центральной точке, чтобы лучше видеть зависимости и обеспечивать лучшую тестируемость.

Существует много IoC-контейнеров, но очень немногие из них пригодны для мобильной разработки. Кроме того, многие из этих контейнеров больше ориентированы на большие проекты с множеством функций, которые не имеют отношения к мобильным приложениям. Я нашел этот вопрос и ответы на StackOverFlow, в котором говорится о популярности и пригодности последних контейнеров IoC. В нашем случае мы были рады использовать TinyIoC .

TinyIoC

TinyIoC — это отличный легкий контейнер, который позволяет вам регистрировать ваши сущности для всего домена приложения. Он достаточно легкий, чтобы быть включенным в большинство небольших проектов, но при этом многофункциональным, чтобы предлагать удобство и гибкость разработчикам. Мы уже давно используем его, и ранее мой коллега Марк Т. писал об этом здесь . TinyIoC поставляется в основном с двумя файлами, самим контейнером и небольшим облегченным messengerHub, который можно использовать для обмена сообщениями между различными сущностями / библиотеками. Плохая новость для меня заключалась в том, что TinyIoC является платформой, поэтому мне пришлось включить другую библиотеку в Android и другую в iOS. Кроме того, я не мог взять эту часть моего кода на мой портативныйбиблиотеки классов. Поэтому я начал думать о том, чтобы перенести это на следующий уровень.

Портативный TinyIoC

Я раздвоил TinyIoC на github , и достаточно просто получил его для компиляции в виде переносимой библиотеки (профиль 102), которую можно использовать на следующих платформах.

1. Xamarin.Android
2. Xamarin.iOS
3. Windows Phone 8.1+
4. .NET 4.0.3+

Все, что мне нужно было сделать, это разделить библиотеку на две разные части: TinyIoC.Core, предназначенный для .NET 4.0 (старый API Reflection), и Portable Wrapper, предназначенный для Portable profile (102), и теперь у нас есть Portable TinyIoC, вы можете найти его на моем аккаунте на github здесь . Я все еще работаю над созданием пакета Nuget или отправкой запроса извлечения, но пока он работает в стабильном состоянии и все модульные тесты пройдены успешно.

Примеры использования TinyIoC на iOS

Как и в большинстве контейнеров IoC, вам нужно зарегистрировать свои зависимости (или включить автоматическое обнаружение :)), поэтому при запуске приложения мы регистрируем так:

public static class Bootstrap
{
    public static void BuckleUp (AppDelegate appDelegate)
    {
            TinyIoCContainer.Current.Register<ITinyMessengerHub, TinyMessengerHub>();
            TinyIoCContainer.Current.Register<AppDelegate> (appDelegate);
 
            TinyIoCContainer.Current.Register<ILogger> (TinyIoCContainer.Current.Resolve<Logger> ());
            TinyIoCContainer.Current.Register<ICloudMobileDataService> (TinyIoCContainer.Current.Resolve<AzureMobileService> ());
 
            TinyIoCContainer.Current.Register<IUserRepository> (TinyIoCContainer.Current.Resolve<UserRepository> ());
    }
}  

Как видите, этот класс Bootstrap вызывается из основного AppDelegate, передавая ему ссылку на делегат приложения, и он регистрирует все зависимости. Помните, что вам нужно регистрировать свои зависимости по порядку, иначе вы можете столкнуться с исключениями. Самое замечательное в том, что вы можете не только издеваться практически над всем и тестировать так, как хотите, но вам также не нужно повторять создание всех зависимостей, чтобы получить определенную сущность. Например, если ваш viewModel принимает 3 параметра в конструкторе, все они являются другими сущностями (облачный сервис, хранилище и т. Д.), Вам нужно только использовать container.Resolve (), и он получит вашу сущность со всеми ее зависимостями. , лото :)
Кроме того , TinyIoC управляет любыми одноразовыми предметами и распоряжаться ими надлежащим образом .

Примеры использования TinyIoC на Android

В Android вы не заметите большой разницы, за исключением размещения точки входа (BuckleUp ()), которая в этом случае вызывается из-за действия MainLauncher. Наш загрузчик Android будет выглядеть так:

public static class Bootstrap
{
        public async static Task BuckleUp(IActivity activity)
        {
            TinyIoCContainer.Current.Register<ITinyMessengerHub, TinyMessengerHub>();
            TinyIoCContainer.Current.Register<IApplication>((IApplication)Android.App.Application.Context);
            TinyIoCContainer.Current.Register<IActivity>(activity);
            // more code is omitted
        }
}

Выводы

В заключении я показал, насколько просто и элегантно использовать контейнеры IoC. Я предпочитаю TinyIoC, потому что он очень легкий, и теперь у нас есть портативная версия, так что у вас больше нет оправданий. Начните смотреть на интеграцию TinyIoC.Portable в ваш следующий мобильный проект, и я хотел бы услышать ваши мысли. В следующем посте мы рассмотрим модульное тестирование Corss-Platform.

TDD в разработке мобильных приложений
1. Модульное тестирование платформо-зависимого кода в разработке мобильных приложений.
2. Portable IoC (Portable.TinyIoC) для мобильной разработки.
3. Кросс-платформенное модульное тестирование — в процессе.