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

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

目前微软的测试框架有MSTestNUnitxUnit 三种,但都不包含Blazor,还好有社区爱好者创建了bUnit 项目方便测试,不过bUnit 并非框架而是项目,所以必须先创建三种测试框架之一的项目再去NuGet 下载bUnit

首先在方案底下创建测试项目BlazorServerMsTest,这边笔者用MSTest 框架,创建好后在项目名称点两下打开csproj文件,会看到Sdk 为"Microsoft.NET.Sdk",要改成"Microsoft.NET.Sdk.Razor",否则Blazor 编译器不会渲染Razor ComponentTargetFramework则要改成net6.0,这样才能跟我们的BlazorServer 项目相容。

接着去NuGet 下载bunit,并且引用主项目BlazorServer,如果要测试的Component 没有用到数据,这样就完成前期作业了,但现实情况都是需要跟数据交互,也就是需要Service,所以要下载可以产生假数据Service,笔者用的是NSubstitute

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

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

我们来测试第一个 div.card 的HTML 结果,先打开网页去复制第一个有card class,这边的User Id 会随数据改变。

下图的19 行创建了bUnit 这个测试实体并赋值给ctx,20 行则利用NSubstitute 创建的假的IUserRepository,21 到23 行调用了 GetUsersAsync() 不过丢了一个假的List(),里面只有一组CustomUserViewModel,这边故意给错误的数据,24 行利用DI 注册 IUserRepository 服务

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 差在哪里,因为我们给的假数据跟预期的不同,所以出错了。

我们把假数据的 UserId 跟 UsreName 改成跟预期的HTML 数据一样,按下ctrl r, t,就能看到通过测试了。

引用:

  1. Creating a new bUnit test project
  2. Writing tests for Blazor components
  3. Mocking with NSubstitute