c# - 使用 WebRequest.RegisterPrefix 模拟 HttpWebResponse/responder

标签 c# .net unit-testing mocking httpwebrequest

我有一些代码正在尝试进行单元测试,据我所知,这根本不可能。有几个类似的问题,其中一些错误地声称可以解决这个问题,但是没有一个可以真正测试我的产品代码。以下是重要行的示例;

            WebRequest req = (WebRequest)WebRequest.Create(url);
            WebResponse resp = (WebResponse)req.GetResponse();
            /*HttpWebResponse httpResp = (HttpWebResponse)resp;

            if (httpResp.StatusCode != (HttpStatusCode)200)
            {
                _log.Error(String.Format("Recieved non-200 status: {0}", httpResp.StatusCode));
                return default(T); // default(T) == null for all reference types
            }*/

在上面的代码中,注释掉的 block 是我的产品中实际应该包含的部分。它上面的两行我不得不在它的地方使用,以使其可进行单元测试。

我的单元测试模拟基于我的示例 here它说它模拟了 HttpWebResponse 但实际上模拟了 WebResponse。据我所知,不可能模拟 HttpWebResponse,因为它的构造函数都已被弃用......这是一个修改该博客文章中的代码的示例;

class TestWebReponse : HttpWebResponse
{
    Stream responseStream;

    /// <summary>Initializes a new instance of <see cref="TestWebReponse"/>
    /// with the response stream to return.</summary>
    public TestWebReponse(Stream responseStream)
    {
        this.responseStream = responseStream;
    }

    /// <summary>See <see cref="WebResponse.GetResponseStream"/>.</summary>
    public override Stream GetResponseStream()
    {
        return responseStream;
    }
}

但是,由于 HttpWebResponse 没有采用 0 个参数的构造函数 错误,上述代码无法编译。有没有人有解决这个问题的方法,它采用类似的机制来拦截产品代码请求,但能够返回 HttpWebResponse?模拟 WebResponse 对于这些类型的应用程序来说并不是很有用(没有其他消费者应该使用 WebRequest/WebResponse 来支持 HttpWebRequest/HttpWebResponse),这是我必须测试的点,所以使用 Moq 或类似的实用程序使我的方法之一返回对象不是一个选项,因为它会只是绕过我要测试的代码(要明确的是两件事;我的请求是否有效以及我们是否正确反序列化响应)。所以对答案的唯一限制是测试代码需要保持与此类似;

string response = JsonConvert.SerializeObject(expected);
WebRequest.RegisterPrefix("test", new TestWebRequestCreate());
TestWebRequest request = TestWebRequestCreate.CreateTestRequest(response);

var client = new FakeProprietaryHTTPClient();
PropietaryDataType res = client.MakeRequestThatReturnsDeserializedPropietaryDataType();
// do asserts against that PropertaryDataType

最佳答案

为了模拟 TestWebRequest、TestWebResponse 类,我将使用称为 PartialMock 的概念。

使用 PartialMock,您可以从 WebRequest、WebResponse 创建一个实例,然后覆盖一些方法。(我们通常将这种方法应用于抽象类)

    class TestWebRequestCreate : IWebRequestCreate
    {

        static WebRequest _nextRequest;
        static readonly object LockObject = new object();

        static public WebRequest NextRequest
        {
            get { return _nextRequest; }
            set
            {
                lock (LockObject)
                {
                    _nextRequest = value;
                }
            }
        }

        public WebRequest Create(Uri uri)
        {
            return _nextRequest;
        }

        public static WebRequest CreateTestRequest(string response)
        {

            var request = MockRepository.GeneratePartialMock<WebRequest>();

            CreateTestWebRequest(request, response);

            NextRequest = request;

            return request;
        }

        private static void CreateTestWebRequest(WebRequest request, string responseStr)
        {
            var requestStream = new MemoryStream();
            request.Stub(x => x.GetRequestStream()).Return(requestStream);
            request.Stub(x => x.Method).PropertyBehavior();
            request.Stub(x => x.ContentType).PropertyBehavior();
            request.Stub(x => x.ContentLength).PropertyBehavior();

            var response = CreateTestWebResponse(responseStr);
            request.Stub(x => x.GetResponse()).Return(response);

        }

        private static WebResponse CreateTestWebResponse(string responseStr)
        {
            var response = MockRepository.GeneratePartialMock<HttpWebResponse>();
            var responseStream = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(responseStr));
            response.Stub(x => x.GetResponseStream()).Return(responseStream);

            return response;
        }
    }

现在一起测试所有类:

        var response = "my response string here";
        WebRequest.RegisterPrefix("test", new TestWebRequestCreate());
        var request = TestWebRequestCreate.CreateTestRequest(response);

        var url = "test://MyUrl";

        var f = WebRequest.Create(url);

        var responce = f.GetResponse() as HttpWebResponse;

        var stream = responce.GetResponseStream();

        var content = new StreamReader(stream).ReadLine();

        Assert.AreEqual(response, content);

用这个概念我在你的链接中模拟了继承。

编辑:

我用了rhino mocks - partial mock在我的示例中。

This是我的解决方案的链接。

关于c# - 使用 WebRequest.RegisterPrefix 模拟 HttpWebResponse/responder,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29022136/

相关文章:

asp.net-mvc - 使用 Recaptcha 对 Action 进行单元测试

java - JUnit 4 测试结果未显示在 Eclipse 中

c# - 在 C# 中自动完成所有建议的三元搜索树

c# - 使用 onServerClick 获取 href 值

c# - 从类库注册Web API Controller

C# 8 异步流与 REST/RPC

c# - 使用 C# 从相机捕获视频流的最简单、最快的方法是什么?

c# - 使用 LINQ 过滤集合

.net - 从构建中获取 BuildAgent 信息

java - 如何在 Java 项目的 Maven 中组织单元、集成、e2e 测试文件夹结构?