Ev.*_*Ev. 7 c# asp.net unit-testing asp.net-web-api asp.net-web-api2
我想在我的WebAPI控制器上"单元"测试一个方法.
此方法依赖于与其一起发送的标头.
所以
HttpContext.Current.Request.Headers["name"]
Run Code Online (Sandbox Code Playgroud)
需要在方法体中有一个值.
这样做的最佳方式是什么?我以为我能够设置ControllerContext来填充HttpContext,但无法让它工作.
我不想使用模拟框架或任何其他第三方工具,因为我的理解是WebAPI2可以很好地使用这个用例.
如果这是最好的方法,我很乐意设置HttpContext.Current.
小智 20
嗨,我可能会晚一点,但我遇到了同样的问题,我在这里是我最终做的.
正如其他人所说,在控制器操作中使用Request.Headers而不是HttpCurrentContext,例如
[Route("")]
[HttpGet]
public IHttpActionResult Get()
{
// The header can have multiple values, I call SingleOrDefault as I only expect 1 value.
var myHeader = Request.Headers.GetValues("X-My-Header").SingleOrDefault();
if (myHeader == "success")
{
return Ok<string>("Success!");
}
return BadRequest();
}
Run Code Online (Sandbox Code Playgroud)
然后很容易创建一个HttpControllerContext并像这样设置request属性:
[TestMethod]
public void Get_HeaderIsValid()
{
// Arrange
var controller = new ConfigurationsController(null);
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("X-My-Header", "success");
// Don't forget these lines, if you do then the request will be null.
controllerContext.Request = request;
controller.ControllerContext = controllerContext;
// Act
var result = controller.Get() as OkNegotiatedContentResult<string>;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual("Success!", result.Content);
}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助 :)
Ps别忘了将Web.Api.Core参考添加到测试项目:)
小智 7
有时,您对编写测试的代码几乎没有控制权.如果它已经被设计为使用HttpContext.Current,并且你不断遇到"Operation is not supported on this platform."像我一样挣扎的错误,这将有所帮助.
public static class NameValueCollectionExtensions
{
public static NameValueCollection AddValue(this NameValueCollection headers, string key, string value)
{
Type t = headers.GetType();
t.InvokeMember("MakeReadWrite", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
t.InvokeMember("InvalidateCachedArrays", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
t.InvokeMember("BaseAdd", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, new object[] { key, new System.Collections.ArrayList() { value } });
t.InvokeMember("MakeReadOnly", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, headers, null);
return headers;
}
}
Run Code Online (Sandbox Code Playgroud)
在同一名称空间中使用该类,您可以添加如下标题:
HttpContext.Current.Request.Headers.AddValue("header_key", "header_value");
Run Code Online (Sandbox Code Playgroud)
当然,如果您不喜欢扩展方法,则可以始终使用包装器方法.
我希望这可以帮助别人.
注意:此答案适用于问题的通用标题,但在此特定情况下,用户具有依赖HttpContext.Current于其无法控制的外部代码.如果这是你的情况,这不是你要走的路.对于大多数其他用户,仍然建议这样做
不要依赖HttpContext.Current于WebAPI.一般建议避免在WebAPI中使用它,其中一个主要原因是单元可测试性.
另请注意,我正在返回,IHttpActionResult这将使测试更容易.
而只是使用控制器成员Request.Headers,然后您可以通过测试中的上下文对象进行设置
public class MyController : ApiController
{
public IHttpActionResult Get()
{
if (Request.Headers. /* insert your code here */)
{
// Do Something
}
}
}
public class TestClass
{
public void Test()
{
// Arrange
var controller = new MyController();
var request = new HttpRequestMessage();
request.Headers... // setup your test here
// Act
var result = controller.Get();
// Assert
// Verify here
}
}
Run Code Online (Sandbox Code Playgroud)
下面是内存集成测试中完整端到端的示例(再次注意,您需要使用整个管道中可用的Request属性而不是HttpContext.Current.此代码取自:WebAPI测试还有一些样式代码中的集成测试.
// Do any setup work
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("Default", "{controller}/{action}");
// Setup in memory server and client
HttpServer server = new HttpServer(config);
HttpClient client = new HttpClient(server);
// Act
HttpResponseMessage response = client.GetAsync("http://localhost/" + requestUrl).Result;
// Assert
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
Assert.Equal(count, response.Content.ReadAsAsync<int>().Result);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10790 次 |
| 最近记录: |