asp.net-mvc - 使用 Asp.Net Web Api 和客户过滤器进行单元测试

标签 asp.net-mvc unit-testing authorize-attribute

我正在 Asp.Net Mvc Web Api 中进行单元测试。 我有 2 个项目

1:Catalog.Api - 这包含所有 Controller

2:Catalog.UnitTests - 这包含 Controller 的单元测试

所有 Controller 都继承了“ApiController”,每个 Controller 都有自定义过滤器 [AuthenticationFilter]。这是我的值(value)观 Controller 。

    [AuthenticationFilter]
    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        public void Post([FromBody]string value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody]string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }

我的习惯是检查授权 token 。在这里

public class AuthenticationFilter: AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)

        {
            var request = actionContext.Request;
            var authorization = request.Headers.Authorization;

            if (authorization == null || authorization.Scheme != "Bearer")
            { 
                ShowAuthenticationError(actionContext, "Authorization required");
                return;
            }

            if (string.IsNullOrEmpty(authorization.Parameter))
            {
                ShowAuthenticationError(actionContext, "Missing Jwt Token");
                return;
            }

            var token = authorization.Parameter;

            var principal = AuthenticateToken(token);
            if (principal == null)
            { 
                ShowAuthenticationError(actionContext, "Invalid token");
                return;
            }
            base.OnAuthorization(actionContext);
        }
        private static void ShowAuthenticationError(HttpActionContext filterContext, string message)
        {
            var responseDTO = new ResponseDTO() { Code = 401, Message = message };
            filterContext.Response =
            filterContext.Request.CreateResponse(HttpStatusCode.Unauthorized, responseDTO);
        }
    }
    public class ResponseDTO
    {
        public int Code { get; set; }
        public string Message { get; set; }
    }

现在在单元测试项目中我有一个类和单元​​测试方法。

        [TestMethod]
        public void CheckFilter()
        {
            try
            {
                var controller = new ValuesController();
                var controllerContext = new HttpControllerContext();
                var request = new HttpRequestMessage();
                request.Headers.Add("Authorization", "bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1bmlxdWVfbmFtZSI6InVhbGkiLCJlbWFpbCI6InVhbGlAaW5yZWFjaGNlLmNvbSIsIm5iZiI6MTU2NDY0NjIyMSwiZXhwI");

                controllerContext.Request = request;
                controller.ControllerContext = controllerContext;

                var result = controller.Get();
                Assert.IsTrue(result.Any());

            }
            catch (Exception ex)
            {
                Assert.Fail();
            }
        }

我通过将 API 项目的引用添加到我的单元测试项目中来调用我的 Controller 。所以所有的 Controller 在单元测试项目中都是可用的。

问题是,当我调用值 Controller 时,它总是返回数据。当我删除请求和 header 时,它也会返回数据,但在那种情况下,这将是未经授权的。

我认为我的自定义过滤器没有调用。应该如何调用它并对用户进行身份验证。

最佳答案

我检查了你的问题并配置了那个问题,基本上你是在直接调用 Controller 。 基本上 Controller 是一个类,当您调用它时,它的行为就像一个简单的类并调用该方法并发回结果。简单明了

但是在你的情况下你有你的 api 项目所以可以这样做。

[TestMethod]
public void CheckFilter()
{
    try
    {
        var config = new HttpConfiguration();
        // This is the resgister method which is written in you Api project. That code is after this method this method because i did the same thing to call my controller.
        Catalog.Api.WebApiConfig.Register(config);
        using (var server = new HttpServer(config))
        {
            var client = new HttpClient(server);

            string url = "http://localhost:PortNumberOfProject/api/values";

            var request = new HttpRequestMessage
            {
                RequestUri = new Uri(url),
                Method = HttpMethod.Get
            };
            request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "Your Token");

            var response = await client.SendAsync(request);
            Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        }
    }
    catch (Exception ex)
    {
        Assert.Fail();
    }
}

这里是Api工程的WebApi Register方法,用于注册Api和Routes。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.MapHttpAttributeRoutes();

        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

这是你的 Controller 。现在调试您的测试并在您的 [AuthenticationFilter] 和 OnAuthorization 方法中添加一个断点。

[AuthenticationFilter]
public class ValuesController : ApiController
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }
}

关于asp.net-mvc - 使用 Asp.Net Web Api 和客户过滤器进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57308170/

相关文章:

asp.net-mvc-3 - MVC 配置授权角色值和强类型角色

asp.net-mvc - mvc 3 session 和授权属性

javascript - 在 HTML 中注入(inject) Javascript 片段

asp.net - 从多个应用程序进行单点登录

c# - 模拟 COM 对象

c# - 在ASP.NET MVC4中,如何重定向到{controller}/{id}?

javascript - 部署后 IE 9 中的 Telerik MVC DatePicker + OnChange 事件问题

asp.net-mvc - ASP.NET MVC : Would it be good practice to have an API Controller action return both View and/or JSON

java - 如何使用 EasyMock 测试 void 方法

c# - 在观察者设计模式单元测试中我们需要测试什么?