我在一个控制器中有一个函数,我正在对它进行单元测试,它需要 http 请求的标头中的值。我无法初始化 HttpContext,因为它是只读的。
我的控制器函数需要“设备 ID”的 http 请求标头值
[TestMethod]
public void TestValuesController()
{
ValuesController controller = new ValuesController();
//not valid controller.HttpContext is readonly
//controller.HttpContext = new DefaultHttpContext();
var result = controller.Get();
Assert.AreEqual(result.Count(), 2);
}
有没有不使用第三方库的直接方法来做到这一点?
我能够以这种方式初始化 httpcontext 和标头:
[TestMethod]
public void TestValuesController()
{
ValuesController controller = new ValuesController();
controller.ControllerContext = new ControllerContext();
controller.ControllerContext.HttpContext = new DefaultHttpContext();
controller.ControllerContext.HttpContext.Request.Headers["device-id"] = "20317";
var result = controller.Get();
//the controller correctly receives the http header key value pair device-id:20317
...
}
与其模拟 HTTPContext,不如将标头映射到方法的参数中可能是一个更好的主意。例如,在此答案底部的控制器中,id
参数设置为名称等于“device-id”的值标头......然后单元测试变为
[TestMethod]
public void TestValuesController()
{
ValuesController controller = new ValuesController();
var result = controller.GetHeaderValue("27");
Assert.AreEqual(result, "27");
}
虽然您可以模拟 HttpContext,但在我看来,除非您别无选择,否则应该避免这种情况。 FromHeaderAttribute 的文档可在此处找到 FromHeaderAttribute Class。
public class ValuesController: Controller
{
public string GetHeaderValue([FromHeader(Name = "device-id")] string id)
{
return id;
}
}
对于需要标头以及 HttpContext 中的其他数据的人,您可以通过 DefaultHttpContext 类的第二个构造函数使用功能初始化上下文来做到这一点:
1. 使用您需要的标题创建一个标题字典:
var headers = new Dictionary<string, StringValues>
{
{ "myHeaderKey", "myHeaderValue" },
};
var headerDictionary = new HeaderDictionary(headers)
2. 使用之前创建的头字典创建一个 HttpRequestFeature:
var requestFeature = new HttpRequestFeature()
{
Headers = headerDictionary,
};
3. 创建一个包含先前创建的特征的特征集合:
var features = new FeatureCollection();
features.Set<IHttpRequestFeature>(requestFeature);
4. 使用特征集合初始化 DefaultHttpContext,并将其设置为控制器的 HttpContext:
var httpContext = new DefaultHttpContext(features);
var controller = new MyController();
controller.ControllerContext = new ControllerContext();
controller.ControllerContext.HttpContext = httpContext;
控制器的上下文将设置正确的标头,您仍然可以通过在实例化 DefaultHttpContext 之前为 featureCollection 设置额外的 HttpContext 属性来根据需要为上下文提供更多数据(例如,查询字符串的 feature.Set<IQueryFeature>(new QueryFeature(...))
)。
PS:有关使用功能来模拟(以及一般的单元测试)HttpContext 的更深入的解释,请参阅:https://weblogs.asp.net/ricardoperes/unit-testing-the-httpcontext-in-controllers
不定期副业成功案例分享