如何编写单元测试用例 IHttpClientFactory
How to write unit test case IHttpClientFactory
我在服务层有一个连接服务的方法,我正在使用 IHttpClientFactory
。我的方法工作正常。现在我正在尝试为此编写单元测试用例。
public async Task<MyObject> MyMethodAsync(string arg1, string arg2)
{
var client = _httpClientFactory.CreateClient("XYZ");
var Authkey = "abc";
var AuthToken = "def";
var headers = new Dictionary<string, string>
{
{ Authkey,AuthToken }
};
client.AddTokenToHeader(headers); //This method set the DefaultRequestheader from the dictionary object
var reqData = new
{
prop1 = "X",
prop2 = "Y"
};//req object
var content = new StringContent(JsonConvert.SerializeObject(reqData), Encoding.UTF8, "application/json");
//This is httpClient Post call for posting data
HttpResponseMessage response = await client.PostAsync("postData", content);
if (!response.IsSuccessStatusCode || response.Content == null)
{
return null;
}
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(response.Content.ReadAsStringAsync().Result);//read the result to an object
return myObject;
}
对于上面的方法,我正在编写测试用例。在这里,我试图设置 Post 方法输出状态代码 OK 并期待
MyMethodAsync
方法为真,因为 PostAsync
为真。在这里我得到一个例外
System.InvalidOperationException : An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
[Test]
public async Task MyMethodAsync_Gets_True()
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("It worked!")
};
//Mock the httpclientfactory
var _httpMessageHandler = new Mock<HttpMessageHandler>();
var mockFactory = new Mock<IHttpClientFactory>();
//Specify here the http method as post
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK
});
var httpClient = new HttpClient(_httpMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
var arg1 = "X";
var arg2 = "D101";
var service = new MyService(_mockAppSettings.Object, mockFactory.Object);
var result = await service.MyMethodAsync(arg1, arg2);
// Assert
Assert.IsNotNull(result);
}
谁能指出我在这里犯了什么错误?
如例外情况所述,您必须
- 要么用绝对 url
调用 PostAsync
- 或者设置HttpClient的
BaseAddress
如果你选择第二个,你需要做的就是:
var httpClient = new HttpClient(_httpMessageHandler.Object);
httpClient.BaseAddress = new Uri("http://nonexisting.domain"); //New code
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
通过此修改,异常将消失。
但是您的测试将失败,因为 response.Content
将是 null
,这就是为什么 MyMethodAsync
将 return 与 null
。
要解决此问题,让我们将设置更改为:
public static async Task MyMethodAsync_Gets_True()
{
//Arrange
MyObject resultObject = new MyObject();
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(resultObject))
};
var _httpMessageHandler = new Mock<HttpMessageHandler>();
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);
...
//Act
var result = await service.MyMethodAsync(arg1, arg2);
//Assert
Assert.NotNull(result);
}
我在服务层有一个连接服务的方法,我正在使用 IHttpClientFactory
。我的方法工作正常。现在我正在尝试为此编写单元测试用例。
public async Task<MyObject> MyMethodAsync(string arg1, string arg2)
{
var client = _httpClientFactory.CreateClient("XYZ");
var Authkey = "abc";
var AuthToken = "def";
var headers = new Dictionary<string, string>
{
{ Authkey,AuthToken }
};
client.AddTokenToHeader(headers); //This method set the DefaultRequestheader from the dictionary object
var reqData = new
{
prop1 = "X",
prop2 = "Y"
};//req object
var content = new StringContent(JsonConvert.SerializeObject(reqData), Encoding.UTF8, "application/json");
//This is httpClient Post call for posting data
HttpResponseMessage response = await client.PostAsync("postData", content);
if (!response.IsSuccessStatusCode || response.Content == null)
{
return null;
}
MyObject myObject = JsonConvert.DeserializeObject<MyObject>(response.Content.ReadAsStringAsync().Result);//read the result to an object
return myObject;
}
对于上面的方法,我正在编写测试用例。在这里,我试图设置 Post 方法输出状态代码 OK 并期待
MyMethodAsync
方法为真,因为 PostAsync
为真。在这里我得到一个例外
System.InvalidOperationException : An invalid request URI was provided. The request URI must either be an absolute URI or BaseAddress must be set.
[Test]
public async Task MyMethodAsync_Gets_True()
{
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("It worked!")
};
//Mock the httpclientfactory
var _httpMessageHandler = new Mock<HttpMessageHandler>();
var mockFactory = new Mock<IHttpClientFactory>();
//Specify here the http method as post
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK
});
var httpClient = new HttpClient(_httpMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
var arg1 = "X";
var arg2 = "D101";
var service = new MyService(_mockAppSettings.Object, mockFactory.Object);
var result = await service.MyMethodAsync(arg1, arg2);
// Assert
Assert.IsNotNull(result);
}
谁能指出我在这里犯了什么错误?
如例外情况所述,您必须
- 要么用绝对 url 调用
- 或者设置HttpClient的
BaseAddress
PostAsync
如果你选择第二个,你需要做的就是:
var httpClient = new HttpClient(_httpMessageHandler.Object);
httpClient.BaseAddress = new Uri("http://nonexisting.domain"); //New code
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
通过此修改,异常将消失。
但是您的测试将失败,因为 response.Content
将是 null
,这就是为什么 MyMethodAsync
将 return 与 null
。
要解决此问题,让我们将设置更改为:
public static async Task MyMethodAsync_Gets_True()
{
//Arrange
MyObject resultObject = new MyObject();
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(resultObject))
};
var _httpMessageHandler = new Mock<HttpMessageHandler>();
_httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync",
ItExpr.Is<HttpRequestMessage>(req => req.Method == HttpMethod.Post),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(response);
...
//Act
var result = await service.MyMethodAsync(arg1, arg2);
//Assert
Assert.NotNull(result);
}