看起来好像您正在尝试包装第 3 方/系统对象以帮助进行单元测试。
说你的出发点是
public class Dependency {
public string Foo() {
return "foo"; // machine, system, time, something else, dependent result
}
public string Bar() {
return "bar";
}
}
public class MySimpleClass {
public string MyFunc() {
return new Dependency().Foo();
}
}
[TestMethod]
public void TestSimple() {
var client = new MySimpleClass();
Assert.AreEqual("foo", client.MyFunc());
}
我们在调用内部创建依赖项,因为我们认为创建成本不如保持依赖项实例重要。这将取决于情况。我们可以很容易地在 ctor 中创建一个 Dependency 并存储我们每次调用的副本。无论哪种方式,我们都无法控制使单元测试混乱的输出。
我们需要为它创建一个代理。
1.为我们需要的成员定义一个接口
很可能,我们不需要使用wrappee的所有成员,所以只在接口中包含我们关心的那些。
public interface IDependencyProxy {
string Foo();
}
2.创建代理类
然后我们创建一个代理类,包装依赖和实现接口。同样,我们可以在开始时或在逐个调用的基础上创建。
public class DependencyProxy : IDependencyProxy {
public string Foo() {
return new Dependency.Foo();
}
}
3. 根据接口定义我们的客户端代码
我们稍微修改我们的客户端代码以使用 IDependencyProxy 接口而不是 Dependency。有几种方法可以做到这一点。我通常使用一个内部 ctor 来获取从公共 ctor 链接的依赖项。(使用 [InternalsVisibleTo] 允许单元测试看到它)
public class MyRevisedClass {
private readonly IDependencyProxy dependency;
public MyRevisedClass()
: this( new DependencyProxy()) {}
internal MyRevisedClass(IDependencyProxy dependency) {
this.dependency = dependency;
}
public string MyFunc() {
return dependency.Foo();
}
}
这允许我们为生产代码提供默认行为(调用 System object),并允许我们模拟单元测试的结果。
[TestMethod]
public void TestRevisedDefault() {
var client = new MyRevisedClass();
Assert.AreEqual("foo", client.MyFunc());
}
[TestMethod]
public void TestRevisedWithMockedDependency() {
var dep = new Mock<IDependencyProxy>();
dep.Setup(mk => mk.Foo()).Returns("bar");
var client = new MyRevisedClass(dep.Object);
Assert.AreEqual("bar", client.MyFunc());
}