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