23 ноября 2011
Adapter pattern. Понимание важности.
Предположим, мы решили использовать уже готовую компоненту, тогда остается выбрать какую именно, но если выбор велик, то перед нами возникает проблема выбора, так как у каждой компоненты различные интерфейсы, различные характеристики по памяти/скорости работы, надежность, различная поддержка со стороны поставщика и цена. На изучении каждой у нас просто нет времени...
Итак, пришло время вспомнить о существовании такого шаблона проектирования как "Адаптер" (Adapter pattern). Я не буду здесь рассказывать про этот шаблон проектирования, а просто постараюсь выделить главную идею:
Всегда оборачивайте стороннюю компоненту своим интерфейсом и адаптируйте ее под себя.
Первая причина, почему это стоит делать очевидна - это устранение жестких зависимостей на стороннюю компоненту, а учитывая, что у зависимостей есть один неприятный момент: с ростом проекта они тоже разрастаются и чем дальше тем сложнее от них избавиться, и в конце концов можно стать "заложником" сторонней компоненты. Казалось бы простое правило, но на практике периодически сталкиваешься с обратным, да и сам порой забываешь обернуть, например, какой-нибудь logger, serializer(json, xml, yaml) или DI/IoC-контейнер, в надежде, что этот инструмент ты не сменишь никогда в проекте.
Вторая причина - это адаптация компоненты "под себя". Адаптируете компоненту таким образом, чтобы Вам было удобно ее использовать.
31 августа 2011
Mock для ICloneable типов
В моей ситуации, было все просто: метод Clone должен возвращать объект (которого на самом деле нет), с наперед известными данными (которые не подлежали бы изменениям). Для наглядности лучше привести исходный код.
Пусть это будет следующий интерфейс:
public interface ISome : ICloneable
{
// некое бизнес-поле
int Value { get; }
}
Итак, тесты вперед, поэтому напишем простой unit-test для метода Clone:
[TestMethod]
public void CloneTest()
{
var original = MakeMockCloneableSome();
// покажем, что и у клонированого объекта
// метод Clone работает как надо
var clone = (ISome)((ISome)((ISome)original.Clone()).Clone()).Clone();
// проверим, что бизнес поле совпадает
Assert.AreEqual(original.Value, clone.Value);
// проверим, что это 2 отдельных объекта
Assert.IsFalse(Object.ReferenceEquals(original, clone));
}
Осталось реализовать метод MakeMockCloneableSome():
ISome MakeMockCloneableSome()
{
var mock = new Mock<ISome>();
// Здесь привычный нам mock бизнес логики...
mock
.Setup(c => c.Value)
.Returns(123);
// Искомый mock метода ICloneable.Clone()
mock
.Setup(c => c.Clone())
.Returns(MakeMockCloneableSome);
return mock.Object;
}
12 мая 2011
Проверяем входные данные
class Bar {}
class Foo
{
Bar _bar;
public Foo(Bar bar)
{
// bar может быть null
if (bar == null)
throw new ArgumentNullException("bar");
_bar = bar;
}
}