Как правильно писать тесты 46 Цикл разработки 46 Структура проекта с тестами 51 Утверждения (Asserts) 52 Утверждения в форме ограничений 54 Категории 56
Вид материала | Тесты |
СодержаниеПримеры реализации по шаблонам Мост+Фабрика |
- Некорректные задания, 1276.79kb.
- К техническому регламенту, 835.7kb.
- Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке разработки, 494.44kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 652.85kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 623.18kb.
- Правительства Российской Федерации от 11. 11. 2005 N 679 о порядке разработки и утверждения, 533.6kb.
- Постановления Правительства Российской Федерации от 11. 11. 2005 n 679 о порядке разработки, 613.63kb.
- Об утверждении требований к схемам теплоснабжения, порядку их разработки и утверждения, 450.79kb.
- Рабочая программа учебной дисциплины. Общие требования, порядок разработки, согласования, 414.77kb.
- Постановлением Правительства Российской Федерации от 11 ноября 2005 г. N 679 о порядке, 1924.26kb.
Примеры реализации по шаблонам Мост+Фабрика25
Целью применения шаблона Мост является отделение замысла от реализации. Клиент использует абстрактную часть, описывающую замысел и не знает, как она реализована. Реализация находится в компонентах, которые предназначены для решения общей задачи, но ничего не знают друг о друге. Общая часть у компонентов – их одинаковые интерфейсы.
Замысел обычно строится так, чтобы его можно было использовать повторно.
Пример 1
Рассмотрим код, реализующий эту идею:
public interface Intention
{
void Echo(string message);
}
internal class Implementation : Intention
{
public void Echo(string message)
{
Console.WriteLine("From the console " + message);
}
}
Клиент ничего не должен знать о реализации, но пока что ему необходимо знать название реализации и следовательно иметь к ней доступ:
Intention obj = new Implementation();
obj.Echo( "hello anybody there");
Пока что это не лучший вариант.
Класс реализации был введен с областью видимости internal, это значит, что компонент, как ему и полагается, будет находиться в отдельной сборке и доступ к нему будут иметь только классы этой сборки. Следовательно, чтобы клиент мог получить экземпляр класса реализации, понадобится класс-помощник. Этим классом будет фабрика.
public class Factory
{
public static Intention Instantiate()
{
return new Implementation();
}
}
Разорвав прямую связь кода, реализующего замысел, с кодом реализации замысла, мы можем поменять реализацию без изменения замысла.
Создадим для нашего кода тест.
[TestMethod]
public void SimpleBridge()
{
Intention obj = Factory.Instantiate();
obj.Echo("hello anybody there");
}
Этот тест будет без проблем выполняться, но он пока что бесполезен, потому что отсутствует способ проверки правильности выводимых данных через метод Echo. В данном случае понадобится mock-объект, т.е. объект, ведущий себя как объект, которому он подражает, но не обладающий его функциональностью. В этом случае нужно сделать mock-объект для класса Console. Обычно mock-объекты создаются для низкоуровневых классов, от которых зависит тестируемый код, чтобы изолированно провести тестирование.
Наш «поддельный» класс Console придется поместить в отдельное пространство имен:
namespace MockObjects
{
public class Console
{
public Console() { }
public static void WriteLine(string message)
{
System.Console.WriteLine("-" + message + "-");
}
}
}
Чтобы его использовать вместе с классом Implementation, нужно указать псевдоним для пространства имен Console:
#define TEST_BUILD
using System;
#if TEST_BUILD
using Console = MockObjects.Console;
#endif
Вообще, mock-объекты нужно создавать в следующих случаях:
- Нужно использовать класс, который в команде делает кто-то другой, но пока не сделал.
- Нужно протестировать функциональность класса изолированно от любых других классов.
В нашем примере для выполнения теста не нужна вся функциональность класса Console. Нам нужно дополнить mock-объект необходимой функциональностью для создания обратной связи, благодаря которой, мы сможем проверить, правильно ли происходит вывод на консоль или нет. Для этого введем в класс Console callback-метод:
using System;
namespace MockObjects
{
public delegate void FeedbackString(string message);
class NoCallbackDefinedException : Exception
{
public NoCallbackDefinedException() : base("No callback is defined") { }
}
public class Callback
{
private static FeedbackString _feedback;
public static FeedbackString CBFeedbackString
{
get
{
if (_feedback == null)
{
throw new NoCallbackDefinedException();
}
return _feedback;
}
set
{
_feedback = value;
}
}
}
public class Console
{
public Console() { }
public static void WriteLine(string message)
{
Callback.CBFeedbackString(message);
}
}
}
Основная идея заключается в том, что метод WriteLine перенаправляет вызов в метод делегата, который обязательно должен предоставить клиент mock-объекта. Делегат должен, например, содержать проверку правильности вывода строки на консоль. При этом вывода на консоль не происходит, потому что вместо System.Console используется mock-объект Console.
private string _strHelloAnybodyThere = "hello anybody there";
[TestMethod]
public void SimpleBridge()
{
Intention obj = Factory.Instantiate();
MockObjects.Callback.CBFeedbackString =
new MockObjects.FeedbackString(this.CallbackSimpleBridge);
obj.Echo(_strHelloAnybodyThere);
}
void CallbackSimpleBridge(string message)
{
string test = "From the console " + _strHelloAnybodyThere;
if (message != test)
{
throw new Exception();
}
}
В итоге мы протестировали метод, который казался нетестируемым.