激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core對Controller進行單元測試的完整步驟

ASP.NET Core對Controller進行單元測試的完整步驟

2020-09-14 16:52Agile.Zhou ASP.NET教程

這篇文章主要給大家介紹了關于ASP.NET Core對Controller進行單元測試的完整步驟,文中通過示例代碼介紹的非常詳細,對大家學習或者使用ASP.NET Core具有一定的參考學習價值,需要的朋友們下面來一起學習學習吧

前言

單元測試對我們的代碼質量非常重要。很多同學都會對業務邏輯或者工具方法寫測試用例,但是往往忽略了對Controller層寫單元測試。我所在的公司沒見過一個對Controller寫過測試的。今天來演示下如果對Controller進行單元測試。以下內容默認您對單元測試有所了解,比如如何mock一個接口。在這里多叨叨一句,面向接口的好處,除了能夠快速的替換實現類(其實大部分接口不會有多個實現),最大的好處就是可以進行mock,可以進行單元測試。

測試Action

下面的Action非常簡單,非常常見的一種代碼。根據用戶id去獲取用戶信息然后展示出來。下面看看如何對這個Action進行測試。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserController : Controller
{
  private readonly IUserService _userService;
  public UserController(IUserService userService)
  {
    _userService = userService;
  }
 
  public IActionResult UserInfo(string userId)
  {
    if (string.IsNullOrEmpty(userId))
    {
      throw new ArgumentNullException(nameof(userId));
    }
 
    var user = _userService.Get(userId);
    return View(user);
  }
 
}

測試代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[TestMethod()]
   public void UserInfoTest()
   {
 
     var userService = new Mock<IUserService>();
     userService.Setup(s => s.Get(It.IsAny<string>())).Returns(new User());
 
     var ctrl = new UserController(userService.Object);
     //對空參數進行assert
     Assert.ThrowsException<ArgumentNullException>(() => {
       var result = ctrl.UserInfo(null);
     });
     //對空參數進行assert
     Assert.ThrowsException<ArgumentNullException>(() => {
       var result = ctrl.UserInfo("");
     });
 
     var result = ctrl.UserInfo("1");
     Assert.IsNotNull(result);
     Assert.IsInstanceOfType(result, typeof(ViewResult));
   }

我們對一個Action進行測試主要的思路就是模擬各種入參,使測試代碼能夠到達所有的分支,并且Assert輸出是否為空,是否為指定的類型等。

對ViewModel進行測試

我們編寫Action的時候還會涉及ViewModel給視圖傳遞數據,這部分也需要進行測試。修改測試用例,加入對ViewModel的測試代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[TestMethod()]
   public void UserInfoTest()
   {
     var userService = new Mock<IUserService>();
     userService.Setup(s => s.Get(It.IsAny<string>())).Returns(new User()
     {
       Id = "x"
     }) ;
 
     var ctrl = new UserController(userService.Object);
     Assert.ThrowsException<ArgumentNullException>(() => {
       var result = ctrl.UserInfo(null);
     });
     Assert.ThrowsException<ArgumentNullException>(() => {
       var result = ctrl.UserInfo("");
     });
 
     var result = ctrl.UserInfo("1");
     Assert.IsNotNull(result);
     Assert.IsInstanceOfType(result, typeof(ViewResult));
     //對viewModel進行assert
     var vr = result as ViewResult;
     Assert.IsNotNull(vr.Model);
     Assert.IsInstanceOfType(vr.Model, typeof(User));
     var user = vr.Model as User;
     Assert.AreEqual("x", user.Id);
   }

對ViewData進行測試

我們編寫Action的時候還會涉及ViewData給視圖傳遞數據,這部分同樣需要測試。修改Action代碼,對ViewData進行賦值:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public IActionResult UserInfo(string userId)
  {
    if (string.IsNullOrEmpty(userId))
    {
      throw new ArgumentNullException(nameof(userId));
    }
 
    var user = _userService.Get(userId);
 
    ViewData["title"] = "user_info";
 
    return View(user);
  }

修改測試用例,加入對ViewData的測試代碼:

  1. [TestMethod()] 
  2.   public void UserInfoTest() 
  3.   { 
  4.     var userService = new Mock<IUserService>(); 
  5.     userService.Setup(s => s.Get(It.IsAny<string>())).Returns(new User() 
  6.     { 
  7.       Id = "x" 
  8.     }) ; 
  9.  
  10.     var ctrl = new UserController(userService.Object); 
  11.     Assert.ThrowsException<ArgumentNullException>(() => { 
  12.       var result = ctrl.UserInfo(null); 
  13.     }); 
  14.     Assert.ThrowsException<ArgumentNullException>(() => { 
  15.       var result = ctrl.UserInfo(""); 
  16.     }); 
  17.  
  18.     var result = ctrl.UserInfo("1"); 
  19.     Assert.IsNotNull(result); 
  20.     Assert.IsInstanceOfType(result, typeof(ViewResult)); 
  21.  
  22.     var vr = result as ViewResult; 
  23.     Assert.IsNotNull(vr.Model); 
  24.     Assert.IsInstanceOfType(vr.Model, typeof(User)); 
  25.     var user = vr.Model as User; 
  26.     Assert.AreEqual("x", user.Id); 
  27.     //對viewData進行assert 
  28.     Assert.IsTrue(vr.ViewData.ContainsKey("title")); 
  29.     var title = vr.ViewData["title"]; 
  30.     Assert.AreEqual("user_info", title); 
  31.   } 

對ViewBag進行測試

因為ViewBag事實上是ViewData的dynamic類型的包裝,所以Action代碼不用改,可以直接對ViewBag進行測試:

  1. [TestMethod()] 
  2.  public void UserInfoTest() 
  3.  { 
  4.    var userService = new Mock<IUserService>(); 
  5.    userService.Setup(s => s.Get(It.IsAny<string>())).Returns(new User() 
  6.    { 
  7.      Id = "x" 
  8.    }) ; 
  9.  
  10.    var ctrl = new UserController(userService.Object); 
  11.    Assert.ThrowsException<ArgumentNullException>(() => { 
  12.      var result = ctrl.UserInfo(null); 
  13.    }); 
  14.    Assert.ThrowsException<ArgumentNullException>(() => { 
  15.      var result = ctrl.UserInfo(""); 
  16.    }); 
  17.  
  18.    var result = ctrl.UserInfo("1"); 
  19.    Assert.IsNotNull(result); 
  20.    Assert.IsInstanceOfType(result, typeof(ViewResult)); 
  21.  
  22.    var vr = result as ViewResult; 
  23.    Assert.IsNotNull(vr.Model); 
  24.    Assert.IsInstanceOfType(vr.Model, typeof(User)); 
  25.    var user = vr.Model as User; 
  26.    Assert.AreEqual("x", user.Id); 
  27.  
  28.    Assert.IsTrue(vr.ViewData.ContainsKey("title")); 
  29.    var title = vr.ViewData["title"]; 
  30.    Assert.AreEqual("user_info", title); 
  31.    //對viewBag進行assert 
  32.    string title1 = ctrl.ViewBag.title; 
  33.    Assert.AreEqual("user_info", title1); 
  34.  } 

設置HttpContext

我們編寫Action的時候很多時候需要調用基類里的HttpContext,比如獲取Request對象,獲取Path,獲取Headers等等,所以有的時候需要自己實例化HttpContext以進行測試。

?
1
2
3
var ctrl = new AccountController();
ctrl.ControllerContext = new ControllerContext();
ctrl.ControllerContext.HttpContext = new DefaultHttpContext();

對HttpContext.SignInAsync進行mock

我們使用ASP.NET Core框架進行登錄認證的時候,往往使用HttpContext.SignInAsync進行認證授權,所以單元測試的時候也需要進行mock。下面是一個典型的登錄Action,對密碼進行認證后調用SignInAsync在客戶端生成登錄憑證,否則跳到登錄失敗頁面。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public async Task<IActionResult> Login(string password)
  {
    if (password == "123")
    {
      var claims = new List<Claim>
      {
       new Claim("UserName","x")
      };
      var authProperties = new AuthenticationProperties
      {
      };
      var claimsIdentity = new ClaimsIdentity(
       claims, CookieAuthenticationDefaults.AuthenticationScheme);
      await HttpContext.SignInAsync(
        CookieAuthenticationDefaults.AuthenticationScheme,
        new ClaimsPrincipal(claimsIdentity),
        authProperties);
      return Redirect("login_success");
    }
 
    return Redirect("login_fail");
  }

HttpContext.SignInAsync其實個時擴展方法,SignInAsync其實最終是調用了IAuthenticationService里的SignInAsync方法。所以我們需要mock的就是IAuthenticationService接口,否者代碼走到HttpContext.SignInAsync會提示找不到IAuthenticationService的service。而IAuthenticationService本身是通過IServiceProvider注入到程序里的,所以同時需要mock接口IServiceProvider。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[TestMethod()]
  public async Task LoginTest()
  {
    var ctrl = new AccountController();
 
    var authenticationService = new Mock<IAuthenticationService>();
    var sp = new Mock<IServiceProvider>();
    sp.Setup(s => s.GetService(typeof(IAuthenticationService)))
      .Returns(() => {
        return authenticationService.Object;
      });
    ctrl.ControllerContext = new ControllerContext();
    ctrl.ControllerContext.HttpContext = new DefaultHttpContext();
    ctrl.ControllerContext.HttpContext.RequestServices = sp.Object;
 
    var result = await ctrl.Login("123");
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, typeof(RedirectResult));
    var rr = result as RedirectResult;
    Assert.AreEqual("login_success", rr.Url);
 
    result = await ctrl.Login("1");
    Assert.IsNotNull(result);
    Assert.IsInstanceOfType(result, typeof(RedirectResult));
    rr = result as RedirectResult;
    Assert.AreEqual("login_fail", rr.Url);
  }

對HttpContext.AuthenticateAsync進行mock

HttpContext.AuthenticateAsync同樣比較常用。這個擴展方法同樣是在IAuthenticationService里,所以測試代碼跟上面的SignInAsync類似,只是需要對AuthenticateAsync繼續mock返回值success or fail。

?
1
2
3
4
5
6
7
8
9
public async Task<IActionResult> Login()
 {
   if ((await HttpContext.AuthenticateAsync()).Succeeded)
   {
     return Redirect("/home");
   }
 
   return Redirect("/login");
 }

測試用例:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[TestMethod()]
public async Task LoginTest1()
{
  var authenticationService = new Mock<IAuthenticationService>();
  //設置AuthenticateAsync為success
  authenticationService.Setup(s => s.AuthenticateAsync(It.IsAny<HttpContext>(), It.IsAny<string>()))
    .ReturnsAsync(AuthenticateResult.Success(new AuthenticationTicket(new System.Security.Claims.ClaimsPrincipal(), "")));
  var sp = new Mock<IServiceProvider>();
  sp.Setup(s => s.GetService(typeof(IAuthenticationService)))
    .Returns(() => {
      return authenticationService.Object;
    });
 
  var ctrl = new AccountController();
  ctrl.ControllerContext = new ControllerContext();
  ctrl.ControllerContext.HttpContext = new DefaultHttpContext();
  ctrl.ControllerContext.HttpContext.RequestServices = sp.Object;
 
  var act = await ctrl.Login();
  Assert.IsNotNull(act);
  Assert.IsInstanceOfType(act, typeof(RedirectResult));
  var rd = act as RedirectResult;
  Assert.AreEqual("/home", rd.Url);
  //設置AuthenticateAsync為fail
  authenticationService.Setup(s => s.AuthenticateAsync(It.IsAny<HttpContext>(), It.IsAny<string>()))
    .ReturnsAsync(AuthenticateResult.Fail(""));
 
  act = await ctrl.Login();
  Assert.IsNotNull(act);
  Assert.IsInstanceOfType(act, typeof(RedirectResult));
  rd = act as RedirectResult;
  Assert.AreEqual("/login", rd.Url);
 
}

Filter進行測試

我們寫Controller的時候往往需要配合很多Filter使用,所以Filter的測試也很重要。下面演示下如何對Fitler進行測試。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MyFilter: ActionFilterAttribute
{
  public override void OnActionExecuting(ActionExecutingContext context)
  {
    if (context.HttpContext.Request.Path.Value.Contains("/abc/"))
    {
      context.Result = new ContentResult() {
        Content = "拒絕訪問"
      };
    }
 
    base.OnActionExecuting(context);
  }
}

對Filter的測試最主要的是模擬ActionExecutingContext參數,以及其中的HttpContext等,然后對預期進行Assert。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
[TestMethod()]
public void OnActionExecutingTest()
{
  var filter = new MyFilter();
  var actContext = new ActionContext(new DefaultHttpContext(),new RouteData(), new ActionDescriptor());
  actContext.HttpContext.Request.Path = "/abc/123";
  var listFilters = new List<IFilterMetadata>();
  var argDict = new Dictionary<string, object>();
  var actExContext = new ActionExecutingContext(
    actContext ,
    listFilters ,
    argDict ,
    new AccountController()
    );
   filter.OnActionExecuting(actExContext);
 
  Assert.IsNotNull(actExContext.Result);
  Assert.IsInstanceOfType(actExContext.Result, typeof(ContentResult));
  var cr = actExContext.Result as ContentResult;
  Assert.AreEqual("拒絕訪問", cr.Content);
 
  actContext = new ActionContext(new DefaultHttpContext(), new RouteData(), new ActionDescriptor());
  actContext.HttpContext.Request.Path = "/1/123";
  listFilters = new List<IFilterMetadata>();
  argDict = new Dictionary<string, object>();
  actExContext = new ActionExecutingContext(
    actContext,
    listFilters,
    argDict,
    new AccountController()
    );
  filter.OnActionExecuting(actExContext);
  Assert.IsNull(actExContext.Result);
}

總結

到此這篇關于ASP.NET Core對Controller進行單元測試的文章就介紹到這了,更多相關ASP.NET Core對Controller單元測試內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://www.cnblogs.com/kklldog/p/unit-test-core-controller.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 欧美在线观看视频网站 | 97久久精品一区二区三区观看 | 欧美一区二区精品夜夜嗨 | 国产精品亚洲三区 | 亚洲午夜网站 | 欧美一级视频网站 | 亚洲精品午夜电影 | 亚洲第一精品在线 | 精品国产一区二区在线观看 | 色综合视频网 | 国产精品一区在线免费观看 | 日本韩国欧美一级片 | 青草av.久久免费一区 | 国产交换3p国产精品 | 国产精品亚洲一区二区三区久久 | 北原夏美av | 日日爱99| 爱高潮www亚洲精品 chengrenzaixian | 九九热视频这里只有精品 | 精精国产xxxx视频在线播放7 | 免费观看视频91 | 爽爽淫人综合网网站 | 久久久人 | 国产在线精品区 | 亚洲第一成人在线视频 | 激情视频免费看 | 日产精品久久久一区二区开放时间 | 国产亚洲高清视频 | :国产精品成人一区二区三区 | 久久久青| 国产亚洲综合一区二区 | 九草av | 中文字幕涩涩久久乱小说 | 91网址在线观看 | 深夜视频福利 | 免费网址黄 | 欧美巨乳在线观看 | 免费人成在线播放 | 日本高清电影在线播放 | 亚洲日本韩国精品 | 国产亚洲精品久久午夜玫瑰园 |