Day29 Blazor 单元测试

开发一个系统最无聊的过程大概就是除错了,尤其是那种尝试对 null 物件取值的错误(Object reference not set to an instance of an object.),这应该是大部分人刚踏入程序领域最常碰到的问题,为了从枯燥的除错过程解脱,这篇就来介绍单元测试。

Blazor 的单元测试跟一般 C# 程序不太一样,主要是检查 Component 的画面呈现逻辑、预期产生的 HTML 标签跟实际画面有无差异,毕竟 Blazor 是以後端语言撰写而渲染的前端框架,如果要验证资料有无错误,就是一般 C# 的单元测试了。

目前微软的测试框架有 MSTest、NUnit 跟 xUnit 三种,但都不包含 Blazor,还好有社群爱好者建立了 bUnit 专案方便测试,不过 bUnit 并非框架而是专案,所以必须先建立三种测试框架之一的专案再去 NuGet 下载 bUnit。

首先在方案底下建立测试专案 BlazorServerMsTest,这边笔者用 MSTest 框架,建立好後在专案名称点两下开启csproj档,会看到 Sdk 为 "Microsoft.NET.Sdk",要改成 "Microsoft.NET.Sdk.Razor",否则 Blazor 编译器不会渲染 Razor Component,TargetFramework 则要改成netcoreapp5.0,这样才能跟我们的 BlazorServer 专案相容。
https://ithelp.ithome.com.tw/upload/images/20210929/20140893T6uourEkRW.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140893GL42f5XReN.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140893Uk11nygSZq.png

接着去 NuGet 下载 bunit,并且参考主专案 BlazorServer,如果要测试的 Component 没有用到资料,这样就完成前置作业了,但现实状况都是需要跟资料互动,也就是需要 Service,所以要下载可以产生假资料的 Service,笔者用的是 NSubstitute。
https://ithelp.ithome.com.tw/upload/images/20210929/20140893AlbqXm7p12.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140893JRKbAK69kP.png

(注:如果想把测试方法都写在 razor档案的 @code 区块,就需要 _Import.razor放置用到的 namespace,但因为笔者都用 code behind 的方式就不放了。)

单元测试中分为三个部分,Arrange、Act、Assert,Arrange 是指测试前的准备,Act 是找出要测试的项目,Assert 则是测试的结果。

我们来测试第一个 div.card 的 HTML 结果,先开启网页去复制第一个有 card class,这边的 User Id 会随资料改变。
https://ithelp.ithome.com.tw/upload/images/20210929/201408934MxLnc0otM.png

下图的19 行创建了 bUnit 这个测试实体并赋值给 ctx,20 行则利用 NSubstitute 建立的假的 IUserRepository,21 到 23 行呼叫了 GetUsersAsync() 不过丢了一个假的 List(),里面只有一组 CustomUserViewModel,这边故意给错误的资料,24 行利用 DI 注册 IUserRepository 服务。
https://ithelp.ithome.com.tw/upload/images/20210929/20140893gv4r0hIxTp.png

27行利用 bUnit 渲染出 UserManagement 并赋值给 cut (component under test),但如果要比较整个 UserManagement 要贴上很多 HTML 标签,所以再用 Find() 找出第一个有 card class 的标签,Find() 用的是 CSS 选择器,代表可以放入标签、class 或是 id 等等。

31行之後就是用找出来的 element 比较我们放进 MarkupMatches() 的 HTML 标签,笔者这边用的是多行,如果不想占据版面的人也可以全部浓缩成一行,bUnit 不会比较断行。

接着就是要实际测试了,可以按 ctrl + r, a 或是从上方的测试页签找到 Test Explorer,然後就能看到测试失败,会告诉你实际的 HTML 跟预期的 HTML 差在哪里,因为我们给的假资料跟预期的不同,所以出错了。
https://ithelp.ithome.com.tw/upload/images/20210929/20140893yfctN7fAkL.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140893yqnibfVvg8.png

我们把假资料的 UserIdUsreName 改成跟预期的 HTML 资料一样,按下 ctrl r, t,就能看到通过测试了。
https://ithelp.ithome.com.tw/upload/images/20210929/20140893b1gY1R5WAZ.png
https://ithelp.ithome.com.tw/upload/images/20210929/20140893pWTZK8G3lN.png

Ref:Creating a new bUnit test project

Ref: Writing tests for Blazor components

Ref: Mocking with NSubstitute


<<:  Day 17 大流量网路安全-Anti-DDoS

>>:  [Day28] Esp32 + IFTTT + Google Sheet - (程序码讲解)

Day7 配对条件范例 (角色,人数上限)

今天我们要自己假订一个配对情境,来做一个比官方稍微复杂一点点的 Demo,并且透过这个模拟情境的实践...

[Day28]进阶挑战花式通灵CTF

再来就是我觉得难度较高的 CTF… 通常 CTF 的赛制因为范围较大,由於题型的机制范围较广,所以可...

Convert Reddit video to GIF

Summary: GIF have become such an important part in...

Day30 - 云端 Study Lab 总结,清除 GCP 专案

Study Lab 总结 在这 30 天中介绍了许多 DevOps 的工具以及工作流程,若读者想要学...