ChatGPT解决这个技术问题 Extra ChatGPT

用于单元测试 .NET 核心 MVC 控制器的模拟 HttpContext?

我在一个控制器中有一个函数,我正在对它进行单元测试,它需要 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?使用控制器的全部意义在于数据来自控制器的参数。如果您的控制器使用 HttpContext 来读取数据,就好像它是一个 WebForms 页面一样,那么您就有问题了。
@PanagiotisKanavos 标头中的值是一条信息,指示呼叫来自哪个移动设备。这是检索正确数据所必需的。设备 ID 位于标头中,因为身份验证需要该 ID,由自定义操作过滤器处理。我可以将设备 ID 作为路由参数传递,但这将是多余的
检查 FromHeaderAttribute 但还要检查重复项。 HttpContext 现在可以通过配置注入
我建议您编辑您的问题以准确指定您想要的内容(访问标题字段以识别移动设备)。 ASP.NET 文档似乎正在经历一个....“过渡”时期,说得好点,缺少文档页面。检查询问如何路由移动设备的 this almost identical question

A
Andrius Naruševičius

我能够以这种方式初始化 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
    ...
}

C
Ciarán Bruen

与其模拟 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;
    }
}

就我而言,IIRC 要求将其包含在 http 标头中,因为需要在 .net 核心中间件组件中评估相同的值
a
adamency

对于需要标头以及 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


关注公众号,不定期副业成功案例分享
关注公众号

不定期副业成功案例分享

领先一步获取最新的外包任务吗?

立即订阅