Skip to main content
 首页 » 编程设计

c#之对依赖于 User.Identity 对象的 ASP.Net Web API Controller 进行单元测试

2024年02月04日31myhome

首先我要说的是,我对单元测试相当陌生,但我现在坚信这一点。我之前的工作中总是有测试员,所以我从来不用担心这个。

我有一个 ASP.Net MVC API 正在替换 Web 服务。 API 从 Web 应用程序获取 HTTP Post,将请求记录到该数据库,然后发出请求并从另一个数据库返回数据。它正在替换的 Web 服务有额外的开销,以确保随请求提交的用户名是登录用户。为了替换它,我使用站点身份验证和关联 Controller 的 User.Identity 对象。

现在我需要为此编写一个单元测试。我可以使用 Moq 为 MVC Controller 模拟经过身份验证的用户,但似乎无法找到如何为 API 模拟经过身份验证的用户。这是我正在尝试做的事情:

... // In the test method 
        DbApiController controller = new DbApiController (); 
        controller.ControllerContext = GetMockContext(); 
... 
 
    private HttpControllerContext GetMockContext() 
    { 
        var identity = new GenericIdentity("testuser"); 
        var controllerContext = new Mock<HttpControllerContext>(); 
        var principal = new Mock<IPrincipal>(); 
        principal.Setup(p => p.IsInRole("SalesAndEstimating")); 
        principal.SetupGet(p => p.Identity.Name).Returns("testuser"); 
        controllerContext.SetupGet(c => c.RequestContext.Principal).Returns(principal.Object); 
 
        return controllerContext.Object; 
    } 

我遇到异常:

System.NotSupportedException: Invalid setup on a non-virtual (overridable in VB) member: mock => mock.RequestContext 

我在这里做错了什么?

更新代码:

        ApiController controller = new DbApiController(); 
 
        var context = new Mock<HttpContextBase>(); 
 
        var identity = new GenericIdentity("testuser"); 
        identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", "1")); 
        var principal = new GenericPrincipal(identity, new[] { "user" }); 
        context.Setup(s => s.User).Returns(principal); 
 
        controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller); 
 
        var results = ((DbApiController)controller).Post(...); 
 
        Assert.AreEqual(results.Success, true); 

在我进行上述更改后,我仍然收到错误“Argument 3: cannot convert from 'System.Web.Http.ApiController' to 'System.Web.Mvc.ControllerBase'”。

请您参考如下方法:

我经常看到这种情况,在单元测试以及应该或不应该测试的内容以及如何测试方面似乎存在很大的误解。

您对功能、业务规则以及任何以某种方式更改数据的内容进行单元测试。您不对 Controller 进行单元测试。

理想情况下,您希望您的 Controller 非常简单,接受一个请求,调用一些服务来完成任何需要完成的事情并返回结果。 Controller 真的应该很轻。如果您像这样编写代码,那么您不需要对它们进行单元测试,您可以对实际执行某些操作的服务进行单元测试。

现在,您仍然想要测试并确保您的 API 正常工作,因此您的下一步是为您的端点编写集成测试,而这正是 Postman 之类的工具可以提供帮助的地方。此工具还有一个优势,即它可以与 CI 服务器集成,这使得集成测试非常容易添加到您的管道中。

所以简而言之,想想你在做什么单元测试,单元测试功能,不要试图测试你正在使用的框架,这是完成的,应该由编写框架的人完成。

当然会使用 Mocking,但是如果您模拟来自数据库的请求和模拟响应,那并不意味着您的代码可以正常工作,数据库可能会以不同的方式工作并抛出错误,即使您的测试通过了,但事实并非如此。不会真正让您的代码变得更好。

单元测试应该是小的、集中的,它们不涉及任何外部系统,比如磁盘上的文件、数据库和其他 API。这样做的原因是您希望它们运行得非常快,即使您有数千个,它们也需要在几秒钟或更短的时间内运行,以便您可以一直运行它们。作为开发人员,您应该一直运行它们以确保您没有破坏任何东西。

不要陷入为了提高任意数字而添加测试的陷阱。