Jon*_*yMC 8 c# dependency-injection abstract-factory
给出一个抽象的工厂实现:
public class FooFactory : IFooFactory {
public IFoo Create(object param1, object param2) {
return new Foo(param1, param2);
}
}
Run Code Online (Sandbox Code Playgroud)
为这堂课写什么单元测试?如何验证param1和param2是否已转发到Foo的创建?我是否必须制作Foo的这些公共属性?这不会破坏封装吗?或者我应该将其留给集成测试?
Mar*_*ann 11
以下是我为这样一个工厂(使用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);
}
Run Code Online (Sandbox Code Playgroud)
它会破坏封装吗?是的,不是......一点点.封装不仅涉及数据隐藏 - 更重要的是,它涉及保护对象的不变量.
我们假设Foo公开了这个公共API:
public class Foo : IFoo
{
public Foo(object param1, object param2);
public void MethodDefinedByInterface();
public object Object1 { get; }
}
Run Code Online (Sandbox Code Playgroud)
虽然该Object1属性略微违反了得墨忒耳法,但它并没有弄乱类的不变量,因为它是只读的.
此外,该Object1属性是具体的Foo类的一部分 - 而不是IFoo接口:
public interface IFoo
{
void MethodDefinedByInterface();
}
Run Code Online (Sandbox Code Playgroud)
一旦您意识到在松散耦合的API中,具体成员就是实现细节,这种仅具体的只读属性对封装的影响非常小.以这种方式思考:
公共Foo构造函数也是具体Foo类的API的一部分,因此只需检查公共API,我们就可以了解它param1并且param2是类的一部分.从某种意义上说,这已经"打破了封装",因此将每个参数作为具体类的只读属性提供并没有太大变化.
这些属性提供的好处是我们现在可以对工厂返回的Foo类的结构形状进行单元测试.
这比重复一组行为单元测试要容易得多,我们必须假设这些测试已经覆盖了具体的Foo类.这几乎就像一个逻辑证明: