Вот как я бы написал один из нескольких модульных тестов для такой фабрики (с xUnit.net ):
[Fact]
public void CreateReturnsInstanceWithCorrectParam1()
{
var sut = new FooFactory();
var expected = new object();
var actual = sut.Create(expected, new object());
var concrete = Assert.IsAssignableFrom<Foo>(actual);
Assert.Equal(expected, concrete.Object1);
}
Это нарушает инкапсуляцию?Да и нет ... немного.Инкапсуляция - это не только сокрытие данных - что более важно, это защита инвариантов объектов .
Предположим, что Foo предоставляет этот публичный API:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
Хотясвойство Object1
слегка нарушает закон Деметры , оно не мешает инвариантам класса, поскольку доступно только для чтения.
Кроме того, свойство Object1
является частьюконкретного класса Foo, а не интерфейса IFoo:
public interface IFoo
{
void MethodDefinedByInterface();
}
Как только вы поймете, что в слабосвязанном API, конкретные элементы являются деталями реализации , такие конкретные только для чтения свойстваимеют очень низкое влияние на инкапсуляцию.Подумайте об этом следующим образом:
Публичный конструктор Foo также является частью API конкретного класса Foo, поэтому, изучая общедоступный API, мы узнаем, что param1
иparam2
являются частью класса.В некотором смысле это уже «нарушает инкапсуляцию», поэтому предоставление каждого параметра в качестве свойств, доступных только для чтения, для конкретного класса практически не меняется.
Такие свойства обеспечивают то преимущество, что теперь мы можем проводить модульное тестирование структурного элемента.Форма класса Foo, возвращаемая фабрикой.
Это гораздо проще, чем повторять набор тестов поведенческих модулей, которые, как мы должны предположить, уже охватывают конкретный класс Foo.Это почти как логическое доказательство:
- Из тестов конкретного класса Foo мы знаем, что он правильно использует / взаимодействует с параметрами своего конструктора.
- Из этих тестов мы также знаем, чтоПараметр конструктора предоставляется как свойство только для чтения.
- Из теста FooFactory мы знаем, что он возвращает экземпляр конкретного класса Foo.
- Кроме того, мы знаем из тестовМетод Create, чтобы его параметры правильно передавались в конструктор Foo.
- QED