如何模拟HttpClientCertificate?
我想单元测试我写的一个动作过滤器。我想嘲笑HttpClientCertificate,但是当我使用MOQ时,我得到异常。 HttpClientCertificate没有公共的默认构造函数。如何模拟HttpClientCertificate?
代码:
//Stub HttpClientCertificate </br>
var certMock = new Mock<HttpClientCertificate>();
HttpClientCertificate clientCertificate = certMock.Object;
requestMock.Setup(b => b.ClientCertificate).Returns(clientCertificate);
certMock.Setup(b => b.Certificate).Returns(new Byte[] { });
这是在.NET中创建单元可测试系统最尴尬的情况。我不可避免地最终为我无法模拟的组件添加了一层抽象。通常,这对于具有不可访问构造函数的类(如本例),非虚拟方法或扩展方法都是必需的。
这里是我使用的模式(我认为它是Adapter pattern),它类似于MVC团队对所有类使用它们进行单元测试的类。
//Here is the original HttpClientCertificate class
//Not actual class, rather generated from metadata in Visual Studio
public class HttpClientCertificate : NameValueCollection {
public byte[] BinaryIssuer { get; }
public int CertEncoding { get; }
//other methods
//...
}
public class HttpClientCertificateBase {
private HttpClientCertificate m_cert;
public HttpClientCertificateBase(HttpClientCertificate cert) {
m_cert = cert;
}
public virtual byte[] BinaryIssuer { get{return m_cert.BinaryIssuer;} }
public virtual int CertEncoding { get{return m_cert.CertEncoding;} }
//other methods
//...
}
public class TestClass {
[TestMethod]
public void Test() {
//we can pass null as constructor argument, since the mocked class will never use it and mock methods will be called instead
var certMock = new Mock<HttpClientCertificate>(null);
certMock.Setup(cert=>cert.BinaryIssuer).Returns(new byte[1]);
}
}
在你的代码,使用HttpClientCertificate
改为使用HttpClientCertificateBase
,您可以实例化这样的 - new HttpClientCertificateBase(httpClientCertificateInstance)
。这样你就可以为你创建一个测试表面来插入模拟对象。
的问题是,你需要创建HttpClientCertificate的模拟时指定构造函数的参数。
var certMock = new Mock<HttpClientCertificate>(ctorArgument);
坏消息是,HttpClientCertificate的构造函数是内部的和发生在一个HttpContext的,所以它可能不会工作。
您仍然可以通过使用FormatterServices使其工作。 GetUninitializedObject()...它不调用构造函数来调用创建实例。 WCF创建请求obj的实例的方式相同。 – Ben 2010-12-18 06:57:20
除非你想编写更多的代码,使类“可测试”,我建议你使用Typemock Isolator,除非另有指定,否则它会寻找第一个c'tor可用 - 公共,内部或私人和假(嘲笑)它的参数你不需要。
创建假对象很简单,只要:
var fakeHttpClientCertificate = Isolate.Fake.Instance<HttpClientCertificate>();
另一种替代方法是使用free Microsoft Moles framework。它将允许您用自己的代理来替换任何.NET方法。查看链接,因为它提供了一个很容易理解的例子。我认为你会发现它比添加间接层以使HttpClientCertificate
进入可测试状态要好得多。
下一次请使用'10101010'编辑器按钮或使用4个空格缩进代码来格式化:-) – 2010-09-03 08:55:09
感谢Peter.I总是被格式化卡住:) – Ben 2010-09-03 09:07:20