+7 (495) 229-0436   shopadmin@itshop.ru 119334, г. Москва, ул. Бардина, д. 4, корп. 3
 
 
Вход
 
 
Каталог
 
 
Подписка на новости
Новости ITShop
Windows 7 и Office: Новости и советы
Обучение и сертификация Microsoft
Вопросы и ответы по MSSQLServer
Delphi - проблемы и решения
Adobe Photoshop: алхимия дизайна
 
Ваш отзыв
Оцените качество магазина ITShop.ru на Яндекс.Маркете. Если вам нравится наш магазин - скажите об этом Google!
 
 
Способы оплаты
 
Курс расчета
 
 1 у.е. = 93.44 руб.
 
 Цены показывать:
 
 
 
 
  
Новости, статьи, акции
 

Создание приложения на WPF с использованием принципов TDD. Часть 1

09.02.2010 10:23

В этой части мы создадим скелет нашего приложения. И первый вопрос, который необходимо решить, это определиться с названием приложения. Есть open-source проект WixEdit, схожий по назначению. Но мы на создание и редактирование проекта не замахиваемся, мы будем только отображать существующий проект, и основная функция будет сборка дистрибутива. После недолгих раздумий принимаем решение назвать проект WixMaker. Создаем в Visual Studio новый проект WixMaker из шаблона WPF Application и добавляем в него ссылки на сборки Composite Application Library. По шагам процесс создания проекта с использованием CAL описан в How to: Create a Solution Using the Composite Application Library.

Также подсоединяем проект к системе контроля версий, например SVN

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

<Window x:Class="WixMaker.Shell"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    xmlns:cal="clr-namespace:Microsoft.Practices.Composite.Wpf.Regions;assembly=Microsoft.Practices.Composite.Wpf"

    Title="WixMaker" Height="400" Width="600">

    <Grid>

        <Grid>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto" />

                <RowDefinition Height="*" />

            </Grid.RowDefinitions>

            <ItemsControl Name="MenuRegion" cal:RegionManager.RegionName="MenuRegion" />

            <ContentControl Name="MainRegion" cal:RegionManager.RegionName="MainRegion" Grid.Row="1" />

        </Grid>

    </Grid>

</Window>

Пока на этом остановимся и займемся модулем. Создадим модуль, который будет заведовать показом содержимого WiX проекта и обработкой команд из меню. Делаем новый подпроект WixProject и в нем класс WixProjectModule. Он будет служить основным связующим звеном для связи содержимого модуля с внешним миром. Теперь мы наследуем класс WixProjectModule от интерфейса IModule, и с помощью IntelliSense создаем реализацию единственного метода этого интерфейса Initialize.

#region IModule Members

public void Initialize()

{

    throw new NotImplementedException();

}

#endregion

Также пропишем наш модуль в загрузчике.

public class Bootstrapper : UnityBootstrapper

{

    protected override DependencyObject CreateShell()

    {

        Shell shell = Container.Resolve<Shell>();

        shell.Show();

        return shell;

    }

    protected override IModuleEnumerator GetModuleEnumerator()

    {

        return new StaticModuleEnumerator().

            AddModule(typeof(WixProjectModule));

    }

}

Это последний шаг, который мы может сделать без тестов. Далее создаем тест для WixProjectModule для метода Initialize, воспользовавшись поддержкой Visual Studio Team System. Щелкнем на названии функции Initialize() и из контекстного меню выберем пункт "Create Unit Tests...".

Согласимся с подтверждающим диалогом, а в диалоге создания нового проекта изменим название проекта на WixProject.Test. Здесь мы следуем методике Microsoft, и называем подпроект с тестами по имени подпроекта, который он тестирует, с добавлением ".Test" в название. Далее студия создаст проект, класс теста для WixProjectModule и тестовый метод InitializeTest() и начальным содержимым.

/// <summary>

///A test for Initialize

///</summary>

[TestMethod()]

public void InitializeTest()

{

    WixProjectModule target = new WixProjectModule(); // TODO: Initialize to an appropriate value

    target.Initialize();

    Assert.Inconclusive("A method that does not return a value cannot be verified.");

}

Мне очень нравится поддержка со стороны Visual Studio в данном случае. Во-первых, проделана большая рутинная работа, а во-вторых, в сгенеренном коде нет ни одной лишней строчки.

Теперь надо решить, что мы будем реализовывать и соответственно проверять. Пойдем по пути наименьших усилий и добавим меню. Так как после добавления меню должно появиться в регионе MenuRegion, то давайте будем проверять, что там что-то появилось. Но для этого надо сделать несколько подготовительных операций. Для начала надо откуда-то получить ссылку на RegionManager, куда мы будем добавлять меню. Это делается просто:

private readonly IRegionManager _regionManager;

public WixProjectModule(IRegionManager regionManager)

{

    _regionManager = regionManager;

}

Не удивляйтесь, но этого будет достаточно. Если вы поставите точку останова в конструкторе и запустите проект, то увидите, что regionManager содержит реальный объект. Первый раз, увидев такой код в выдернутом из недр интернета примере, я ничего не понял. Откуда возьмется реализация IRegionManager? Собственно это и явилось побудительной причиной познакомиться с Composite Application Library. Здесь мы в первый раз в нашем проекте сталкиваемся с паттерном Inversion of Control (IoC) который в данном случае реализован через другой, более специализированный паттерн Dependency Injection (DI). А это значит, что всю необходимую работу для нас делает Unit Container. Помимо того что мы избежали внесения сильной связи в наш модуль, а то и еще хуже Singleton, мы получили отличную возможность для модульного тестирования, чем мы сейчас и воспользуемся. Для этого в нашем тесте вместо реального RegionManager мы передадим поддельный объект (Mock object) с необходимой нам для теста функциональностью.

public class MockRegionManager : IRegionManager

{

    private Dictionary<string, IRegion> _regions = new Dictionary<string, IRegion>();

    public IDictionary<string, IRegion> Regions

    {

        get { return _regions; }

    }

    public void AttachNewRegion(object regionTarget, string regionName)

    {

        throw new NotImplementedException();

    }

    public IRegionManager CreateRegionManager()

    {

        throw new NotImplementedException();

    }

}

Как видите, код подделки прост. И он и не должен быть сложным. Мы не пытаемся полностью сымитировать поведение объекта, а только ту минимальную часть, которая нужна нам для конкретного теста. Если для другого теста нам понадобится дополнительная функциональность, надо будет оценить, что лучше: дописать новую функциональность в уже существующий поддельный объект, с вероятностью, что это затронет уже отлаженные тесты. Или написать новую реализацию поддельного объекта, только с той функциональностью, которая нужна для нового теста. Подобным образом реализуем поддельный объект для IRegion. Теперь у нас есть все для первого теста.

Возвращаемся к нашему тесту, а конкретно к строчке с TODO, который предлагает нам дописать код инициализации. Как видим, комментарий был поставлен не зря. Заменяем эту строчку на

var regionManager = new MockRegionManager();

WixProjectModule target = new WixProjectModule(regionManager);

Также добавляем поддельный регион для меню

var menuRegion = new MockRegion();

regionManager.Regions.Add("MenuRegion", menuRegion);

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

Assert.AreEqual(1, menuRegion.AddedViews.Count);

Полностью тест выглядет так

[TestMethod]

public void InitializeTest()

{

   var regionManager = new MockRegionManager();

   WixProjectModule target = new WixProjectModule(regionManager);

   var menuRegion = new MockRegion();

   regionManager.Regions.Add("MenuRegion", menuRegion);

   target.Initialize();

   Assert.AreEqual(1, menuRegion.AddedViews.Count);

}

Тест готов. Нам надо его запустить, чтобы получить первоначальный негативный результат. Это важный момент. Если вы сначала напишите функциональность, а потом тест, и он сразу пройдет, то это не значит, что новый кусок кода работает правильно. Может быть, тест проходит и без него. Запустить тест можно или из контекстного меню, встав внутрь тестового метода и выбрав "Run Tests" или через меню Test->Run->Test In Current Context.Получаем первый результат

Полностью Error Message:

Test method WixProject.Test.WixProjectModuleTest.InitializeTest threw exception:  System.NotImplementedException: The method or operation is not implemented..

Ну что же, мы получили красный цвет и конкретное сообщение, которое указывает что делать дальше. Создаем MainMenu класс, отнаследованный от UserControl.

<UserControl x:Class="WixProject.MainMenu"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>

        <Menu Grid.Row="0" IsMainMenu="True">

            <MenuItem Header="File">

                <MenuItem Header="Open" />

            </MenuItem>

        </Menu>

    </Grid>

</UserControl>

Наконец добрались до сути и добавляем наше меню в регион

public void Initialize()

{

   IRegion menuRegion = _regionManager.Regions["MainMenu"];

   menuRegion.Add(new MainMenu());

}

Здесь мы использовали еще одну специализированную реализацию шаблона IoC, а именно шаблон Service Locator. Запускаем заново тест, и получаем опять красный цвет и сообщение:

Test method WixProject.Test.WixProjectModuleTest.InitializeTest threw exception:  System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary..   

Так, ситуация проясняется. Мы ошиблись в названии региона. Если бы не тест, мы при запуске приложения просто бы увидел пустое окно, и нам бы просто оставалось гадать, в чем дело. Исправляем название региона на MenuRegion, запускаем тест снова и наконец видим зеленый цвет.

Запускаем наше приложение, видим окно приложения с меню.

Да, кажется, по функциональности мы не сильно продвинулись. На самом деле мы создали вполне работоспособный и главное легко расширяемый макет приложения, который мы и будем наполнять.

Ссылки по теме

  
Помощь
Задать вопрос
 программы
 обучение
 экзамены
 компьютеры
Бесплатный звонок
ICQ-консультанты
Skype-консультанты

Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 
Бестселлеры
Курсы обучения "Atlassian JIRA - система управления проектами и задачами на предприятии"
Microsoft Windows 10 Профессиональная 32-bit/64-bit. Все языки. Электронный ключ
Microsoft Office для Дома и Учебы 2019. Все языки. Электронный ключ
Курс "Oracle. Программирование на SQL и PL/SQL"
Курс "Основы TOGAF® 9"
Microsoft Office 365 Персональный 32-bit/x64. 1 ПК/MAC + 1 Планшет + 1 Телефон. Все языки. Подписка на 1 год. Электронный ключ
Курс "Нотация BPMN 2.0. Ее использование для моделирования бизнес-процессов и их регламентации"
 

О нас
Интернет-магазин ITShop.ru предлагает широкий спектр услуг информационных технологий и ПО.

На протяжении многих лет интернет-магазин предлагает товары и услуги, ориентированные на бизнес-пользователей и специалистов по информационным технологиям.

Хорошие отзывы постоянных клиентов и высокий уровень специалистов позволяет получить наивысший результат при совместной работе.

В нашем магазине вы можете приобрести лицензионное ПО выбрав необходимое из широкого спектра и ассортимента по самым доступным ценам. Наши менеджеры любезно помогут определиться с выбором ПО, которое необходимо именно вам. Также мы проводим учебные курсы. Мы приглашаем к сотрудничеству учебные центры, организаторов семинаров и бизнес-тренингов, преподавателей. Сфера сотрудничества - продвижение бизнес-тренингов и курсов обучения по информационным технологиям.



 

О нас

 
Главная
Каталог
Новинки
Акции
Вакансии
 

Помощь

 
Общая справка
Как оформить заказ
Тарифы доставки
Способы оплаты
Прайс-лист
Карта сайта
 

Способы оплаты

 

Проекты Interface Ltd.

 
Interface.ru   ITShop.ru   Interface.ru/training   Olap.ru   ITnews.ru  
 

119334, г. Москва, ул. Бардина, д. 4, корп. 3
+7 (495) 229-0436   shopadmin@itshop.ru
Проверить аттестат
© ООО "Interface Ltd."
Продаем программное обеспечение с 1990 года