如何模拟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[] { }); 
+0

下一次请使用'10101010'编辑器按钮或使用4个空格缩进代码来格式化:-) – 2010-09-03 08:55:09

+0

感谢Peter.I总是被格式化卡住:) – Ben 2010-09-03 09:07:20

这是在.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的,所以它可能不会工作。

+0

您仍然可以通过使用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进入可测试状态要好得多。