) 环球关注:重新整理 .net core 实践篇——— 测试控制器[四十九]_华尔街制鞋网

环球关注:重新整理 .net core 实践篇——— 测试控制器[四十九]

首页>滚动 > 正文
2023-06-15 06:26:19

来源:博客园

前言

其实就是官方的例子,只是在此收录整理一下。

正文

测试控制器测试的是什么呢?

测试的是避开筛选器、路由、模型绑定,就是只测试控制器的逻辑,但是不测试器依赖项。


(资料图片仅供参考)

代码部分:

https://github.com/dotnet/AspNetCore.Docs/tree/main/aspnetcore/mvc/controllers/testing/samples/

第一个例子:

[Fact]public async Task Index_ReturnsAViewResult_WithAListOfBrainstormSessions(){// arrangevar mockRepo = new Mock();mockRepo.Setup(repo => repo.ListAsync()).ReturnsAsync(GetTestSessions());var controller = new HomeController(mockRepo.Object);// actvar result = await controller.Index();// assertvar viewResult = Assert.IsType(result);var model = Assert.IsAssignableFrom>(viewResult.ViewData.Model);Assert.Equal(2, model.Count());}private List GetTestSessions(){var sessions = new List();sessions.Add(new BrainstormSession(){DateCreated = new DateTime(2016, 7, 2),Id = 1,Name = "Test One"});sessions.Add(new BrainstormSession(){DateCreated = new DateTime(2016, 7, 1),Id = 2,Name = "Test Two"});return sessions;}

Index_ReturnsAViewResult_WithAListOfBrainstormSessions 命名规则:

Index 是测试的方法。

ReturnsAViewResult 是结果

WithAListOfBrainstormSessions 是条件

var viewResult = Assert.IsType(result);var model = Assert.IsAssignableFrom>(viewResult.ViewData.Model);Assert.Equal(2, model.Count());

有3个测试的地方:

  1. 测试结果类型是ViewResult

  2. 测试viewResult.ViewData.Model,是IEnumerable的派生

  3. 测试model的数量为2

第二个例子:

[Fact]public async Task IndexPost_RetrunsBadRequestResult_WhenModelStateInvalid(){// Arrangevar mockRepo = new Mock();mockRepo.Setup(repo => repo.ListAsync()).ReturnsAsync(GetTestSessions());var controller = new HomeController(mockRepo.Object);controller.ModelState.AddModelError("SessionName", "Required");var newSession = new HomeController.NewSessionModel();// Actvar result = await controller.Index(newSession);// Assertvar badRequestResult = Assert.IsType(result);Assert.IsType(badRequestResult.Value);}

进行ModelState 验证, 因为没有走mvc,那么需要自己设置验证信息。

[Fact]public async Task IndexPost_ReturnsARedirectAndAddsSession_WhenModelStateIsValid(){// Arrangevar mockRepo = new Mock();mockRepo.Setup(repo => repo.AddAsync(It.IsAny())).Returns(Task.CompletedTask).Verifiable();var controller = new HomeController(mockRepo.Object);var newSession = new HomeController.NewSessionModel(){SessionName = "Test Name"};// Actvar result = await controller.Index(newSession);// Assertvar redirectToActionResult = Assert.IsType(result);Assert.Null(redirectToActionResult.ControllerName);Assert.Equal("Index", redirectToActionResult.ActionName);mockRepo.Verify();}

这里主要介绍的是mockRepo.Verify(),在mockRepo 模拟方法的时候AddAsync设置,传入的类型要是BrainstormSession。

如果不是的话,那么就会抛出异常。

it 还有很多其他的选项,比如不能为空等。

然后为什么这里是两个测试呢? 这里要介绍的是单元测试,必须要覆盖测试,分布测试不同情况。

例子3:

那么下面测试SessionController:

这里开始有些变化了,注意观察:

[Fact]public async Task IndexReturnsARedirectToIndexHomeWhenIdIsNull(){// Arrangevar controller = new SessionController(sessionRepository: null);// Actvar result = await controller.Index(id: null);// Assertvar redirectToActionResult =Assert.IsType(result);Assert.Equal("Home", redirectToActionResult.ControllerName);Assert.Equal("Index", redirectToActionResult.ActionName);}[Fact]public async Task IndexReturnsContentWithSessionNotFoundWhenSessionNotFound(){// Arrangeint testSessionId = 1;var mockRepo = new Mock();mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId)).ReturnsAsync((BrainstormSession)null);var controller = new SessionController(mockRepo.Object);// Actvar result = await controller.Index(testSessionId);// Assertvar contentResult = Assert.IsType(result);Assert.Equal("Session not found.", contentResult.Content);}public async Task IndexReturnsViewResultWithStormSessionViewModel(){var testSessionId = 1;var mockRepo = new Mock();mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId)).ReturnsAsync(GetTestSessions().FirstOrDefault(s => s.Id == testSessionId));var controller = new SessionController(mockRepo.Object);// actvar result = controller.Index(testSessionId);// Assertvar viewResult = Assert.IsType(result);var model = Assert.IsType(viewResult.ViewData.Model);Assert.Equal("Test One", model.Name);Assert.Equal(2, model.DateCreated.Day);Assert.Equal(testSessionId, model.Id);}private List GetTestSessions(){var sessions = new List();sessions.Add(new BrainstormSession(){DateCreated = new DateTime(2016, 7, 2),Id = 1,Name = "Test One"});sessions.Add(new BrainstormSession(){DateCreated = new DateTime(2016, 7, 1),Id = 2,Name = "Test Two"});return sessions;}

上面不仅将方法的各种情况都覆盖了,还注意到命名:

以前命名是测试方式_测试结果_测试条件。

现在命名是一个句子来描述了,这样做的目的是使得写代码的人读起来更加通顺。

// Arrangeint testSessionId = 1;var mockRepo = new Mock();mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId)).ReturnsAsync(GetTestSessions().FirstOrDefault(s => s.Id == testSessionId));

这个点值得关注一下, 比如说去模拟GetByIdAsync的返回信息,是可以进行自我实现的,而不是单纯的传递一个值。

前面的例子验证了查询这块,那么第四个例子,来验证创建这块。

[Fact]public async Task Create_ReturnsBadRequest_GivenInvalidModel(){    // Arrange & Act    var mockRepo = new Mock();    var controller = new IdeasController(mockRepo.Object);    controller.ModelState.AddModelError("error", "some error");    // Act    var result = await controller.Create(model: null);    // Assert    Assert.IsType(result);}
[Fact]public async Task Create_ReturnsHttpNotFound_ForInvalidSession(){    // Arrange    int testSessionId = 123;    var mockRepo = new Mock();    mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId))        .ReturnsAsync((BrainstormSession)null);    var controller = new IdeasController(mockRepo.Object);    // Act    var result = await controller.Create(new NewIdeaModel());    // Assert    Assert.IsType(result);}
[Fact]public async Task Create_ReturnsNewlyCreatedIdeaForSession(){// Arrangeint testSessionId = 1;string testName = "test name";string testDescription = "test description";var testSession = GetTestSession();var mockRepo = new Mock();mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId)).ReturnsAsync(testSession);var controller = new IdeasController(mockRepo.Object);var newIdea = new NewIdeaModel(){Description = testDescription,Name = testName,SessionId = testSessionId};mockRepo.Setup(repo => repo.UpdateAsync(testSession)).Returns(Task.CompletedTask).Verifiable();// Actvar result = await controller.Create(newIdea);// Assertvar okResult = Assert.IsType(result);var returnSession = Assert.IsType(okResult.Value);mockRepo.Verify();Assert.Equal(1, returnSession.Ideas.Count());Assert.Equal(testName, returnSession.Ideas.LastOrDefault().Name);Assert.Equal(testDescription, returnSession.Ideas.LastOrDefault().Description);}private BrainstormSession GetTestSession(){return new BrainstormSession(){DateCreated = new DateTime(2016, 7, 1),Id = 2,Name = "Test Two",};}

值得注意的是最后这个:

UpdateAsync 这个并不需要我们过多的逻辑去测试,这个是单元测试,而不需要关注依赖的细节。

然后这个有个Verifiable,这个是验证什么的呢? 验证UpdateAsync 传入的对象是testSession,如果不是的话,那么:

[Fact]public async Task Create_ReturnsNewlyCreatedIdeaForSession(){// Arrangeint testSessionId = 1;string testName = "test name";string testDescription = "test description";var testSession = GetTestSession();var mockRepo = new Mock();mockRepo.Setup(repo => repo.GetByIdAsync(testSessionId)).ReturnsAsync(testSession);var controller = new IdeasController(mockRepo.Object);var newIdea = new NewIdeaModel(){Description = testDescription,Name = testName,SessionId = testSessionId};mockRepo.Setup(repo => repo.UpdateAsync(GetTestSession())).Returns(Task.CompletedTask).Verifiable();// Actvar result = await controller.Create(newIdea);// Assertvar okResult = Assert.IsType(result);var returnSession = Assert.IsType(okResult.Value);mockRepo.Verify();Assert.Equal(1, returnSession.Ideas.Count());Assert.Equal(testName, returnSession.Ideas.LastOrDefault().Name);Assert.Equal(testDescription, returnSession.Ideas.LastOrDefault().Description);}

比如我这样写,那么会报错:

那么其实记住的是,单元测试验证的输入和输出。

比如这里的xuit, 对于验证输出是很好验证的,那么为什么使用moq这个东西呢,理由也很简单哈,那就是验证传参,也就是验证输入。

这里还有另外一个问题,当要开始Assert时候,我们应该一个怎么样的顺序去验证呢?

一个基本的思路就是:

  1. 先验证输出的类型
var actionResult = Assert.IsType>(result);var createdAtActionResult = Assert.IsType(actionResult.Result);var returnValue = Assert.IsType(createdAtActionResult.Value);
  1. 然后验证输入的参数
mockRepo.Verify();
  1. 最后验证细节
Assert.Equal(2, returnValue.Ideas.Count());Assert.Equal(testName, returnValue.Ideas.LastOrDefault().Name);Assert.Equal(testDescription, returnValue.Ideas.LastOrDefault().Description);

上面就是验证单元控制器的测试的基本思路了,其实的方法验证的差不多。

下一节集成测试。

标签:

THE END
免责声明:本文系转载,版权归原作者所有;旨在传递信息,不代华尔街制鞋网的观点和立场。

相关热点

新华社电 上海市文化和旅游局近日发布《上海市密室剧本杀内容备案管理规定(征求意见稿)》,并截至12月8日面向社会公众广泛征求意见。这
2021-11-19 13:46:03
《中国证券报》17日刊发文章《备战2022 基金经理调仓换股布新局》。文章称,距离2021年结束仅剩一个多月,基金业绩分化明显。部分排名靠前
2021-11-19 13:46:03
交通运输部办公厅 中国人民银行办公厅 中国银行保险监督管理委员会办公厅关于进一步做好货车ETC发行服务有关工作的通知各省、自治区、直
2021-11-19 13:45:58
新华社北京11月17日电 题:从10月份市场供需积极变化看中国经济韧性新华社记者魏玉坤、丁乐读懂中国经济,一个直观的视角就是市场供需两端
2021-11-19 13:45:58
全国教育财务工作会议披露的消息称,2020年,中国国家财政性教育经费投入达4 29万亿元,占GDP总量的4 206%,我国国家财政性教育经费支出占G
2021-11-19 13:45:48
如果你也热爱“种草”,前方高能预警!让你心心念念、“浏览”忘返的网络平台,可能早已成为一块块“韭菜地”。近日,据《半月谈》报道,有...
2021-11-19 13:45:48
日前,工业和信息化部印发《“十四五”信息通信行业发展规划》(以下简称《规划》),描绘了未来5年信息通信行业的发展趋势。《规划》指出...
2021-11-19 13:45:40
本报讯(中青报·中青网记者 周围围)2021年快递业务旺季正式拉开帷幕。国家邮政局监测数据显示,仅11月1日当日,全国共揽收快递包裹5 69
2021-11-19 13:45:40
人民网曼谷11月17日电 (记者赵益普)17日上午,中国援柬埔寨第七批200万剂科兴新冠疫苗抵达金边国际机场。当天,柬埔寨政府在机场举行了
2021-11-19 13:45:35
金坛压缩空气储能国家试验示范项目主体工程一角受访者供图依托清华大学非补燃压缩空气储能技术,金坛压缩空气储能项目申请专利百余项,建立
2021-11-19 13:45:35
视觉中国供图42亿立方米据有关部门预计,今年山西煤炭产量有望突破12亿吨,12月份山西外送电能力将超过900万千瓦,今冬明春煤层气产量将达4
2021-11-19 13:44:34
14省份相继发布2021年企业工资指导线——引导企业合理提高职工工资今年以来,天津、新疆、内蒙古、陕西、西藏、山东、江西、山西、福建、四
2021-11-19 13:44:34
中新网客户端北京11月18日电 (记者 谢艺观)“一条路海角天涯,两颗心相依相伴,风吹不走誓言,雨打不湿浪漫,意济苍生苦与痛,情牵天下喜
2021-11-19 13:44:31
近日,交通运输部等三部门发布《关于进一步做好货车ETC发行服务有关工作的通知》。通知提到,对不具备授信条件的用户,商业银行可在依法合
2021-11-19 13:44:31
欧莱雅面膜陷优惠“年度最大”风波 涉及该事件集体投诉超6000人次美妆大牌双十一促销翻车?近日,因预售价格比双十一现货贵出66%,欧莱雅
2021-11-19 13:44:13
43 6%受访者会在工作两三年后考虑跳槽54 3%受访者认为跳槽对个人职业发展有利有弊如今对不少年轻人来说,想对一份工作“从一而终”不太容易
2021-11-19 13:44:13
超八成受访青年表示如有机会愿意开展副业 规划能力最重要64 4%受访青年指出做副业跟风心态最要不得如今,“身兼数职”已成为年轻人当中的
2021-11-19 13:44:01
发展氢能正当其时【科学随笔】氢能是一种二次能源,它通过一定的方法利用其他能源制取,具有清洁无污染、可储存、与多种能源便捷转换等优点
2021-11-19 13:44:01
“千杯不醉”的解酒“神药”能信吗?专家:网红“解酒药” 其实不算药俗话说,“酒逢知己千杯少”,酒一直是国人饭桌上至关重要的存在。尽...
2021-11-19 13:43:57
最新文章

相关推荐