最新要闻
- 云南一地多次发生巨响震动!官方回应:初判为浅源性地震-环球快资讯
- 天天观速讯丨英伟达太强 AMD最强显卡尚无客户采购:软件干不过CUDA
- 小米14设计定了:标准版小直屏 Pro版极窄微曲屏-环球热头条
- 快看点丨给全世界每个人发钱 OpenAI创始人这么飘了?
- 比尔·盖茨抵达北京:就健康和环境问题向中国取经|当前简讯
- (上接第一版)
- 无敌时间_关于无敌时间介绍
- 创业板注册制IPO申请“开闸”满三年:千企竞逐上市梦 创业板加速构建创新资本中心
- 中央美术学院教授黄永玉去世 为具有重大影响力的艺术家
- 张柏芝发文呼吁大家关注糖尿病年轻化 减轻职场人群“高甜负担”
- 多地提前进入“烧烤模式” 新疆东部和南疆盆地有35℃以上高温
- 重金买下哈利波特老宅的屋主感到后悔 朝圣粉丝令其苦不堪言
- 歌手苏醒晒出自己和“球王”梅西的合影 兴奋之情溢于言表
- 腾讯音乐与原神达成深度战略合作 经典之声再度重逢
- 2023年“惠购湖北”家电消费券即将发放 总计投入财政资金3亿元
- 对标英伟达A100 国产GPU沐曦MXC500成功点亮:仅用时5个小时|世界消息
手机
iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?
- 警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案
- 男子被关545天申国赔:获赔18万多 驳回精神抚慰金
- 3天内26名本土感染者,辽宁确诊人数已超安徽
- 广西柳州一男子因纠纷杀害三人后自首
- 洱海坠机4名机组人员被批准为烈士 数千干部群众悼念
家电
焦点速讯:重新整理 .net core 实践篇——— 测试控制器[四十九]
前言
其实就是官方的例子,只是在此收录整理一下。
正文
测试控制器测试的是什么呢?
(资料图)
测试的是避开筛选器、路由、模型绑定,就是只测试控制器的逻辑,但是不测试器依赖项。
代码部分:
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个测试的地方:
测试结果类型是ViewResult
测试viewResult.ViewData.Model,是IEnumerable
的派生 测试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时候,我们应该一个怎么样的顺序去验证呢?
一个基本的思路就是:
- 先验证输出的类型
var actionResult = Assert.IsType>(result);var createdAtActionResult = Assert.IsType(actionResult.Result);var returnValue = Assert.IsType(createdAtActionResult.Value);
- 然后验证输入的参数
mockRepo.Verify();
- 最后验证细节
Assert.Equal(2, returnValue.Ideas.Count());Assert.Equal(testName, returnValue.Ideas.LastOrDefault().Name);Assert.Equal(testDescription, returnValue.Ideas.LastOrDefault().Description);
结
上面就是验证单元控制器的测试的基本思路了,其实的方法验证的差不多。
下一节集成测试。
关键词:
焦点速讯:重新整理 .net core 实践篇——— 测试控制器[四十九]
云南一地多次发生巨响震动!官方回应:初判为浅源性地震-环球快资讯
天天观速讯丨英伟达太强 AMD最强显卡尚无客户采购:软件干不过CUDA
小米14设计定了:标准版小直屏 Pro版极窄微曲屏-环球热头条
快看点丨给全世界每个人发钱 OpenAI创始人这么飘了?
比尔·盖茨抵达北京:就健康和环境问题向中国取经|当前简讯
(上接第一版)
无敌时间_关于无敌时间介绍
创业板注册制IPO申请“开闸”满三年:千企竞逐上市梦 创业板加速构建创新资本中心
中央美术学院教授黄永玉去世 为具有重大影响力的艺术家
张柏芝发文呼吁大家关注糖尿病年轻化 减轻职场人群“高甜负担”
多地提前进入“烧烤模式” 新疆东部和南疆盆地有35℃以上高温
重金买下哈利波特老宅的屋主感到后悔 朝圣粉丝令其苦不堪言
歌手苏醒晒出自己和“球王”梅西的合影 兴奋之情溢于言表
腾讯音乐与原神达成深度战略合作 经典之声再度重逢
2023年“惠购湖北”家电消费券即将发放 总计投入财政资金3亿元
Set 接口及其常用方法
对标英伟达A100 国产GPU沐曦MXC500成功点亮:仅用时5个小时|世界消息
奶奶带孙子时邻居反馈“不像他爸” 去做亲子鉴定后崩溃:真不是
微软创始人比尔盖茨抵达北京!2019年以来首次访问
小米米家首款自发电动感单车采用南芯芯片:支持20W有线/无线快充
环球看热讯:买下《哈利波特》电影中房子的屋主后悔了 每天都有粉丝来打卡
澳琴企业首次亮相第九届上交会_热资讯
百度文心一格×京东618:打造电商行业首个AI线下广告,节省80%制作成本|焦点快看
环球视讯!人人有份!湖北将发放3亿元消费券:最大面额500元 京东可用
世界热点评!作别“战国七雄” 中国快递业变天了:进入三足鼎立
阿里巴巴集团公关部将独立成公关公司?知情人士:假的-环球关注
微控制器实时操作系统实践5选择IDE 全球短讯
文心一言 VS 讯飞星火 VS chatgpt (41)-- 算法导论5.4 5题
【环球播资讯】破“3”!30年期国债收益率创2006年以来新低
有关交朋友的成语典故_与朋友有关的成语典故
男子花120万买二手奥迪R8 开了三年发现竟是全损泡水车
精选!商汤元萝卜AI下棋机器人围棋版发布:棋艺达职业九段
150元只能划半小时!杭州西湖划船刺客运营方被罚12万|环球讯息
开发者怒赞macOS 14真香!喊话微软:这三大功能值得Windows 12借鉴
索泰预热全新PGF系列旗舰显卡:或为RTX 4090 环球头条
天天视点!加个电池就是新能源?被欧洲拒绝的混动,才是埋藏最深的骗局!
当前动态:中兴Axon 50 Ultra开启预约:卫星通信疑似取消
当前关注:18岁小伙骑共享单车5000公里到新疆:送给自己的成人礼
捡漏超大额券:森马男女款网红飞织鞋69元 透气百搭
留给BBA的时间不多了!理想L6谍照首次曝光 将于明年正式交付_环球短讯
“熊猫血”男子献血证塞满了抽屉 21年献出3.5个人的全部血量:行为让人敬佩
焦点速读:2023重庆璧山小学报名入口
当 GraphQL 遇上图数据库,便有了更方便查询数据的方式 当前短讯
6月14日北向资金最新动向(附十大成交股)_全球今头条
iQOO Neo8 Pro顶配版明天首销:1TB UFS 4.0规格 3699价位独此一款
《神鬼寓言4》女主角外观遭玩家吐槽:这是在比丑!-全球快资讯
国产新能源深蓝SL03路口起火烧毁 厂商:系发动机护板卷入麦秆自燃引起
【全球快播报】Win11企业版默认启用SMB签名导致Bug:微软发布解决方案
每日看点!用上宁德时代麒麟电池!新款哪吒S曝光:能跑1075km
[SDOI2008] 递归数列
【全球播资讯】ssh免密登录、服务器安全
烷基计数
风口上的AIGC,技术岗动不动年薪百万,甚至重金难求? 天天新消息
MegEngine 使用小技巧:如何做 MegCC 的模型性能评测
焦点速看:认知型通用大模型“360智脑”升级4.0,国内首发“文生视频”多模态功能
4连板联明股份:股价短期内涨幅明显高于上证指数及行业板块指数,但公司基本面未发生重大变化
多种矿物质元素 依能天然苏打水15瓶到手34.91元
世界快资讯:天气炎热 亚洲象开启“避暑模式”!网友:真羡慕了
超越《塞尔达传说:王国之泪》:《暗黑破坏神4》登顶英国周销量榜-新资讯
国产AI天花板!讯飞星火iOS内测版上线:已覆盖PC、手机等主流系统 短讯
微资讯!地表67℃!火焰山进入炙烤模式:景区为游客增配防暑药品
FTL没有映射,跟发工资没有钱有什么区别 要闻
【全球新要闻】奇妙敏捷之旅·青岛站,现场燃爆了!
联盟送福利:云上掘金,开启你收入的第二增长曲线 全球新视野
机器硬件监控,最简单的方案,没有之一
因为余华的一封信,莫言要去东澳岛读书了
恒生指数14日收跌0.58%结束五连涨
科创浪潮奔涌大湾区
PDF问世30周年 每年6月15日成“PDF日”
中国空间站美景请查收!央视解析全新构型:三舱三船
最高额外降温3℃:猫头鹰针对AMD AM5插槽CPU推出散热支架-热门
世界观天下!苹果蝉联2023年凯度BrandZ最具价值全球百强榜首:腾讯跻身十强
中国自研唯一入选项目!《王者荣耀亚运版本》发布:共计63个英雄
毕马威:力争在2030年将毕马威全球的直接和间接碳排放在2019年基础上减半 今日热议
世界时讯:SpringBoot中Redis的基础使用
利用 PHP 特性绕 WAF 测试 环球聚看点
linux-DNS域名解析
世界即时看!2种GaussDB(DWS)查看作业运行信息方式
收评:两市窄幅波动沪指微跌0.14% CPO概念股领涨 大消费主题反弹
热头条丨【新华500】新华500指数(989001)14日涨0.03%
世界今热点:层层梯田上红山荞麦播种忙 全产业链带动农民增收
【当前独家】AMD自杀式降价 讯景RX 7900 XT显卡到手5299元(首发7399)
男生说猫屎臭被头上扣饭?官方回应:已经处理
天天滚动:与K60 Ultra同台发!Redmi 2K新平板曝光:只要千元
外卖小哥从10多米高大桥跳水救人:见义勇为获奖3万、免费上大学
焦点热讯:中国第一条时速350铁路明日调图:动车组重联 运力翻倍
2023内蒙古师范大学附属中学英才计划招生简章
618大促|解析平台、商家和消费者必须面对的三大风险
【技术积累】Python中的NumPy库【二】|天天滚动
全球快资讯丨Springboot定时任务集成shedLock锁
今日热搜:开放中国依然是外商投资高地
每日动态!晋升第一人口大国后 印度将成为全球第一大手机市场:多谢苹果
不是录播!梅西即将在淘宝开启首次直播
华为又背锅?理想粉丝暗指华为发动舆论攻击:李想出面澄清
亚运会倒计时101天!杭州开通“亚运号”定制专列
国内最畅销SUV排名出炉:特斯拉Model Y反超比亚迪宋Plus拿下第一
天天快看点丨大文件上传功能在标签服务的简单应用和代码实现
Aurelia教程_编程入门自学教程_菜鸟教程-免费教程分享
让电池新规为电动自行车加把“安全锁” 全球热点评