Kerry 的筆記本
  • Table of contents
  • Kerry的Mac裝機必要
  • ASP.NET Core 教育訓練文件
    • .NET 9 OpenAPI 介紹與教學
    • 目錄
    • ASP.NET Core Authentication系列(一)理解Claim, ClaimsIdentity, ClaimsPrincipal
    • ASP.NET Core Authentication系列(三)Cookie選項
    • ASP.NET Core Authentication系列(二)實現認證、登錄和註銷
    • ASP.NET Core Authentication系列(四)基於Cookie實現多應用間單點登錄(SSO)
    • ASP.NET Core Consul 教學
    • ASP.NET Core Hangfire 排程管理
    • ASP.NET Core KeyCloak 實作
    • ASP.NET Core NLog-依照Environment使用Nlog.Config檔案
    • ASP.NET Core NLog-如何使用 NLog 將 log 寫到檔案
    • ASP.NET Core Nlog-發送訊息到ElasticSearch
    • 目錄
    • ASP.NET Core Quartz.NET 管理介面
    • ASP.NET Core RDLC 報表設計
    • ASP.NET Core SFTP (使用第三方套建 SSH.Net) - 類別庫為案例
    • ASP.NET Core 中使用 HttpReports 進行接口統計,分析, 可視化, 監控,追踪等
    • ASP.NET 使用 MassTransit 與 RabbitMQ,實現事件發佈、訂閱
    • Asp.Net Core 分散式Session – 使用 Redis
    • ASP.NET Core 前台會員修改個人資料
    • ASP.NET Core 前台會員忘記密碼與重設密碼
    • ASP.NET Core 前台會員登入
    • ASP.NET Core 前台會員註冊
    • ASP.NET Core 呼叫 API 發生 CORS 錯誤
    • ASP.NET Core 如何套網頁設計樣版
    • ASP.NET Core 客製化Model Validation 預設錯誤訊息
    • ASP.NET Core 後台查詢頁面教學
    • ASP.NET Core 網站生命週期
    • ASP.NET Feature Management 使用說明與教學
    • ASP.NET RulesEngine 介紹
    • ASP.NET WinForms APP 程式安裝檔
    • LinePay 支付完成後返回 LINE 應用而不跳出外部瀏覽器
    • EntityFramework
      • EF Core Migrations 完整教學手冊
      • EntityFramework Core DB Migrations
      • 使用 Entity Framework Core (EF Core) 的 Migrations 功能進行版本控制
    • NET 6
      • .NET 6 Autofac範例
      • .NET 6 Automapper範例
      • .NET 6 BenchmarkDotNet範例
      • .NET 6 Bogus範例
      • .NET 6 Dapper範例
      • .NET 6 Dapper語法說明
      • .NET 6 EFCore範例
      • .NET 6 EFCore語法說明
      • .NET 6 EPPlus圖表範例
      • .NET 6 EPPlus範例
      • .NET 6 Hangfire範例
      • .NET 6 HttpClient單元測試範例
      • .NET 6 MailKit前置作業
      • .NET 6 MailKit範例
      • .NET 6 Moq範例
      • .NET 6 NLog範例
      • .NET 6 NLog進階範例
      • .NET 6 Serilog範例
      • .NET 6 Serilog進階範例
      • .NET 6 Telegram.Bot前置作業
      • .NET 6 Telegram.Bot範例
      • .NET 6 Text.Json範例
      • .NET 6 swagger授權
      • .NET 6 swagger範例
      • .NET 6 xUnit範例
      • .NET 6 取得appsettings檔案內容
      • .NET 6 更改回傳Json時為大駝峰命名
      • .NET 6 解決System.Text.Json序列化後會將所有非ASCII轉為Unicode
    • WDMIS
      • CORS
      • FeatureManagement
      • Serilog
      • Spectre.Console
      • 資料模型實戰:從 MSSQL 設計到 .NET 8 WebAPI 實作(以刀具管理為例)
  • Azure
    • 如何在 ASP.NET CORE 5.0 WEB 應用程序中實現 AZURE AD 身份驗證
    • Azure App Configuration 使用教學
    • Azure Blob Storage
    • Azure DevOps 持續整合(CI) + Artifacts
  • CSharp
    • ASP.NET await 與 wait 的差異
    • AutoMapper —— 類別轉換超省力
    • C# 中的 HTTPClient — 入門指南
    • C# 正則表達式:從零到英雄指南
    • C# 集合, List<> 取交集、差集、聯集的方法
    • C#單元測試教學
    • CORS 介紹與設定方式
    • CSharp Coding Conventions
    • Using jQuery Unobtrusive AJAX in ASP.NET Core Razor Pages
    • 深入Dapper.NET源碼
    • 菜雞與物件導向
      • 菜雞與物件導向 (0): 前言
      • 菜雞與物件導向 (1): 類別、物件
      • 菜雞與物件導向 (10): 單一職責原則
      • 菜雞與物件導向 (11): 開放封閉原則
      • 菜雞與物件導向 (12): 里氏替換原則
      • 菜雞與物件導向 (13): 介面隔離原則
      • 菜雞與物件導向 (14): 依賴反轉原則
      • 菜雞與物件導向 (15): 最少知識原則
      • 菜雞與物件導向 (2): 建構式、多載
      • 菜雞與物件導向 (3): 封裝
      • 菜雞與物件導向 (4): 繼承
      • 菜雞與物件導向 (5): 多型
      • 菜雞與物件導向 (6): 抽象、覆寫
      • 菜雞與物件導向 (7): 介面
      • 菜雞與物件導向 (8): 內聚、耦合
      • 菜雞與物件導向 (9): SOLID
      • 菜雞與物件導向 (Ex1): 小結
  • DBeaver
    • 如何強制讓 DBeaver 在 Mac 上使用英文介面
  • DesignPattern
    • OAuth
    • Repository 模式 (Repository Pattern)
    • Single Sign On 實作方式介紹 (CAS)
    • 【SOP製作教學】新手適用,SOP範例、流程圖、製作流程全公開!
    • 【SOP製作教學】流程圖教學、重點範例、BPMN符號介紹!
    • 【SOP製作教學】流程圖符號整理、BPMN2.0進階符號教學!
    • 多奇數位 C# 程式碼撰寫規範 (C# Coding Guideline)
    • 軟體分層設計模式 (Software Layered Architecture Pattern)
    • 開源程式碼檢測平台 SonarQube
    • 菜雞新訓記
      • 菜雞新訓記 (0): 前言
      • 菜雞新訓記 (1): 使用 Git 來進行版本控制吧
      • 菜雞新訓記 (2): 認識 Api & 使用 .net Core 來建立簡單的 Web Api 服務吧
      • 菜雞新訓記 (3): 使用 Dapper 來連線到資料庫 CRUD 吧
      • 菜雞新訓記 (4): 使用 Swagger 來自動產生可互動的 API 文件吧
      • 菜雞新訓記 (5): 使用 三層式架構 來切分服務的關注點和職責吧
      • 菜雞新訓記 (6): 使用 依賴注入 (Dependency Injection) 來解除強耦合吧
      • 菜雞新訓記 (7): 使用 Fluent Validation 來驗證參數吧
  • DevOps
    • Repository 模式 (Repository Pattern)
    • pipeline工具研究
    • 單例模式 (Singleton Pattern)
    • 單元測試
    • 軟體分層設計模式 (Software Layered Architecture Pattern)
    • 雙重檢查鎖定模式 (Double-Checked Locking Pattern)
  • Docker
    • Docker 中部署 .NET 8 Web App 並支援 HTTPS
    • Docker指令大全
    • 第七章 安裝Nomad
    • Docker - 第三章 | 安裝 MSSQL
    • Docker - 第九章 | 安裝 datalust seq
    • 第二章 docker-compose 教學
    • Docker - 第五章 | 安裝 Redis
    • 第八章 安裝SonarQube
    • Docker - 第六章 | 安裝RabbitMQ
    • 第十一章 安裝 VtigerCRM
    • 第十二章 安裝KeyCloak
    • Docker - 第十章 | 安裝 Redmine
    • 第四章 安裝MySQL
    • Docker Desktop (含更改 Docker Image 路徑)
  • Git
    • Git Flow 指令大全(完整指令整理) 🚀
    • Git 安裝及配置SSH Key
    • Git 建立到上傳
    • 將現有專案的遠端儲存庫直接更改為新的儲存庫
    • Git 流程規劃
    • Git 語法大全
    • 30 天精通 Git 版本控管
      • 30 天精通 Git 版本控制
        • 第 01 天:认识 Git 版本控制
        • 第 02 天:在 Windows 平台必装的三套 Git 工具
        • 第 03 天:建立仓库
        • 第 04 天:常用的 Git 版本控制指令
        • 第 05 天:了解仓库、工作目录、物件与索引之间的关系
        • 第 06 天:解析 Git 资料结构 - 物件结构
        • 第 07 天:解析 Git 资料结构 - 索引结构
        • 第 08 天:关于分支的基本观念与使用方式
        • 第 09 天:比对文件与版本差异
        • 第 10 天:认识 Git 物件的绝对名称
        • 第 11 天:认识 Git 物件的一般参照与符号参照
        • 第 12 天:认识 Git 物件的相对名称
        • 第 13 天:暂存工作目录与索引的变更状态
        • 第 14 天: Git for Windows 选项设定
        • 第 15 天:标签 - 标记版本控制过程中的重要事件
        • 第 16 天:善用版本日志 git reflog 追踪变更轨迹
        • 第 17 天:关于合并的基本观念与使用方式
        • 第 18 天:修正 commit 过的版本历史记录 Part 1
        • 第 19 天:设定 .gitignore 忽略清单
        • 第 20 天:修正 commit 过的版本历史记录 Part 2
        • 第 21 天:修正 commit 过的版本历史记录 Part 3
        • 第 22 天:修正 commit 过的版本历史记录 Part 4 (Rebase)
        • 第 23 天:修正 commit 过的版本历史记录 Part 5
        • 第 24 天:使用 GitHub 远端仓库 - 入门篇
        • 第 25 天:使用 GitHub 远端仓库 - 观念篇
        • 第 26 天:多人在同一个远端仓库中进行版控
        • 第 27 天:通过分支在同一个远端仓库中进行版控
        • 第 28 天:了解 GitHub 的 fork 与 pull request 版控流程
        • 第 29 天:如何将 Subversion 项目汇入到 Git 仓库
        • 第 30 天:分享工作中几个好用的 Git 操作技巧
      • zh-tw
        • 第 01 天:認識 Git 版本控管
        • 第 02 天:在 Windows 平台必裝的三套 Git 工具
        • 第 03 天:建立儲存庫
        • 第 04 天:常用的 Git 版本控管指令
        • 第 05 天:了解儲存庫、工作目錄、物件與索引之間的關係
        • 第 06 天:解析 Git 資料結構 - 物件結構
        • 第 07 天:解析 Git 資料結構 - 索引結構
        • 第 08 天:關於分支的基本觀念與使用方式
        • 第 09 天:比對檔案與版本差異
        • 第 10 天:認識 Git 物件的絕對名稱
        • 第 11 天:認識 Git 物件的一般參照與符號參照
        • 第 12 天:認識 Git 物件的相對名稱
        • 第 13 天:暫存工作目錄與索引的變更狀態
        • 第 14 天: Git for Windows 選項設定
        • 第 15 天:標籤 - 標記版本控制過程中的重要事件
        • 第 16 天:善用版本日誌 git reflog 追蹤變更軌跡
        • 第 17 天:關於合併的基本觀念與使用方式
        • 第 18 天:修正 commit 過的版本歷史紀錄 Part 1
        • 第 19 天:設定 .gitignore 忽略清單
        • 第 20 天:修正 commit 過的版本歷史紀錄 Part 2
        • 第 21 天:修正 commit 過的版本歷史紀錄 Part 3
        • 第 22 天:修正 commit 過的版本歷史紀錄 Part 4 (Rebase)
        • 第 23 天:修正 commit 過的版本歷史紀錄 Part 5
        • 第 24 天:使用 GitHub 遠端儲存庫 - 入門篇
        • 第 25 天:使用 GitHub 遠端儲存庫 - 觀念篇
        • 第 26 天:多人在同一個遠端儲存庫中進行版控
        • 第 27 天:透過分支在同一個遠端儲存庫中進行版控
        • 第 28 天:了解 GitHub 的 fork 與 pull request 版控流程
        • 第 29 天:如何將 Subversion 專案匯入到 Git 儲存庫
        • 第 30 天:分享工作中幾個好用的 Git 操作技巧
  • Hands-On Labs - LineBotSDK 實作手札 (C#, .net core)
    • 00. 如何申請LINE Bot
    • CLI
      • 使用CLI來發送新的Channel Access Token(LINE Bot)
      • 使用CLI免費發送LINE Notify通知
    • basic
      • 如何發送LINE訊息(Push Message)
      • 如何發送LINE Template Messages
      • 如何發送ImageMap訊息
      • 如何發送Flex Message
      • 如何在訊息後面加上QuickReply快捷選項
    • liff
      • Lab 21: 建立第一個LIFF應用
    • webhook
      • 如何建立可Echo的基本LINE Bot
      • 如何在WebHook中取得用戶個人資訊(名稱、頭像、狀態)
      • 如何在WebHook中取得用戶上傳的圖片(Bytes)
  • Markdown
    • Markdown Cheatsheet 中文版
    • Markdown語法大全
    • 使用HackMD建立書本目錄
    • 使用HackMD建立簡報
  • SAP ABAP
    • ABAP開發環境和總體介紹
    • SAP MM模塊常用表總結
    • SAP QM數據庫表清單
    • SAP欄位與表的對應關係
  • SQL Server
    • [SQL SERVER] Like in
    • SQL Server 中,移除資料庫中所有的關聯限制
    • SQL Server 刪除資料庫中所有資料表
    • SQL Server View、Function 及 Stored Procedure 定義之快速備份
    • SSMS v18 清除登入畫面中,下拉選單歷史紀錄
    • [MS SQL]如何透過Database Mail進行郵件發送
    • [SQL SERVER]撰寫Stored Procedure小細節
    • 使用 Data Migration Assistant 移轉 SQL Server 資料庫與帳戶
    • 使用SSIS創建同步資料庫數據任務
  • Tools
    • 免費 FTP 伺服器 FileZilla Server 安裝教學 (新版設定)
  • VisualStudio
    • .NET CLI 指令碼介紹
    • Visual Studio 使用 Git 版本控制
    • 使用 Visual Studio 2022 可透過 .editorconfig 鎖定文字檔案的儲存編碼格式分享
  • Web API
    • ASP.NET Core 6 Web API 進行 JWT 令牌身份驗證
    • [ASP.NET Core]如何使用SwaggerAPI說明文件
    • ASP.NET Core Web Api實作JWT驗證筆記
    • ECFIT API 範例
    • JWT Token Authentication And Authorizations In .Net Core 6.0 Web API
    • 微服務架構 - 從狀態圖來驅動 API 的設計
  • Windows
    • [C#] 伺服器監控常用語法 (事件檢視器、CPU 硬碟使用率、程式執行狀況)
    • Configure IIS Web Server on Windows Server 2019
    • Log Paser Studio 分析 IIS W3C Log
    • Windows Server 2019 如何安裝 IIS 運行 ASP.NET 專案
    • 如何檢查安裝在 IIS 上的 .NET Core Hosting Bundle 版本
    • [IIS] 如何解決網站第一個請求 Request 特別慢 ?
    • IIS 不停機更版設置
    • SQL Server 2019 Standard 繁體中文標準版安裝
    • WINDOWS共用資料夾的網路認證密碼放在哪?如何清除?
    • 如何設定 ASP.NET CORE 網站應用程式持續執行在 IIS 上
  • 專案管理
    • SSDLC (Secure Software Development Life Cycle)
    • 系統開發原則
    • MIS及專案管理-使用Redmine
      • 第10章 - [日常管理]MIS部門週會工作進度追蹤
      • 第11章 - [日常管理]MIS部門主管月會報告管理
      • 第12章 - [日常管理]機房工作日誌
      • 第13章 - [日常管理]MIS部門耗用工時及工作進度檢討
      • 第14章 - [日常管理]MIS文件知識庫
      • 第15章 - [日常管理]整理及管理分享
      • 第16章 - [異常管理]使用者問題回報系統
      • 第17章 - [異常管理]資安事件及異常紀錄
      • 第18章 - [異常管理]整理及管理分享
      • 第19章 - [變革管理]MIS的專案及專案管理五大階段
      • 第1章 - [MIS及專案管理]中小企業MIS的鳥事
      • 第20章 - [變革管理]MIS的新專案管理:起始階段
      • 第21章 - [變革管理]MIS的新專案管理:規劃階段
      • 第22章 - [變革管理]MIS的新專案管理:執行階段
      • 第23章 - [變革管理]MIS的新專案管理:監控階段
      • 第24章 - [變革管理]MIS的新專案管理:結束階段
      • 第25章 - [變革管理]整理及管理分享
      • 第26章 - [ISMS管理]ISMS平台整體規劃
      • 第27章 - [ISMS管理]ISMS文管中心
      • 第28章 - [ISMS管理]ISMS表單紀錄的管理
      • 第29章 - [ISMS管理]整理及管理分享
      • 第2章 - [MIS及專案管理]專案管理的概念及MIS應用
      • 第30章 - 初心、來時路及感謝:系列文章總結回顧
      • 第3章 - [MIS及專案管理]管理工具的選擇
      • 第4章 - [Redmine]Redmine的安裝及設定
      • 第5章 - [Redmine]Redime系統邏輯說明
      • 第6章 - [Redmine]自行建立及維護表單
      • 第7章 - [Redmine]專案版面的規劃
      • 第8章 - [日常管理]AR管理
      • 第9章 - [日常管理]資訊服務申請
  • 微服務架構
    • DDD + CQRS + MediatR 專案架構
    • 微服務架構 #2, 按照架構,重構系統
    • 淺談微服務與網站架構的發展史
    • API First Workshop 設計概念與實做案例
      • API First #1 架構師觀點 - API First 的開發策略 - 觀念篇
      • API First #2 架構師觀點 - API First 的開發策略 - 設計實做篇
    • 基礎建設 - 建立微服務的執行環境
      • Part #1 微服務基礎建設 - Service Discovery
      • Part #2 微服務基礎建設 - 服務負載的控制
      • Part #3 微服務基礎建設 - 排隊機制設計
      • Part #4 可靠的微服務通訊 - Message Queue Based RPC
      • Part #5 非同步任務的處理機制 - Process Pool
    • 實做基礎技術 API & SDK Design
      • API & SDK Design #1, 資料分頁的處理方式
      • API & SDK Design #2, 設計專屬的 SDK
      • API & SDK Design #3, API 的向前相容機制
      • API & SDK Design #4, API 上線前的準備 - Swagger + Azure API Apps
      • API & SDK Design #5 如何強化微服務的安全性 API Token JWT 的應用
    • 建構微服務開發團隊
      • 架構面試題 #1, 線上交易的正確性
      • 架構面試題 #2, 連續資料的統計方式
      • 架構面試題 #3, RDBMS 處理樹狀結構的技巧
      • 架構面試題 #4 - 抽象化設計;折扣規則的設計機制
    • 架構師觀點 - 轉移到微服務架構的經驗分享
      • Part #1 改變架構的動機
      • Part #2 實際改變的架構案例
    • 案例實作 - IP 查詢服務的開發與設計
      • 容器化的微服務開發 #1 架構與開發範例
      • 容器化的微服務開發 #2 IIS or Self Host
  • 系統評估
    • RPA 與 WebAPI 評估
    • 數位轉型:從現有系統到數位化的未來
    • 數位轉型:從現有系統到數位化的未來
  • 面試
    • CV_黃子豪_2024
    • HR 問題集
    • .NET 工程師 面試問題集
    • 資深工程師 問題集
    • 資深開發人員 / 技術主管
    • 題目
Powered by GitBook
On this page
  1. CSharp

C#單元測試教學

前言

本人在公司負責導入單元測試框架,這是寫給公司內部的教學文件,稍微編修後分享給各位

本篇文章內容包含:

  • 單元測試介紹

  • 為什麼要寫測試?如何寫測試?

  • 單元測試框架 MSTest、NUnit、xUnit

  • 可讀性更佳的 Fluent Assertions

  • 程式碼覆蓋率 (Code Coverage)

  • 免費程式碼覆蓋率分析工具 dotCover

  • E2E 測試工具 Selenium

什麼是測試?

模擬程式碼的執行行為,來進行正確性檢驗的測試工作。

單元測試 (Unit testing)

單元測試指的是最小單元的測試,一個單元就是單個程式、函式、過程等。對於物件導向程式設計,最小單元就是方法,包括基礎類別、抽象類別、或者衍生類別中的方法。

這種測試由開發人員自行撰寫。

整合測試 (Integration testing)

整合測試是指將 2 個以上的類別整合一起測試,以確保它們之間的連動是否正常。例如:單元測試分別測試了購物車、轉帳的功能。而整合測試就一口氣將 2 步驟一次跑完,所以整合測試一定是跨類別的。

這種測試通常由專門的測試團隊撰寫,但大部份情況由某模組的負責人寫。

端對端測試 (End-to-end testing) (E2E testing)

使用者(一端)對真實系統(另一端)進行測試。從用戶的角度、環境出發,實際操作系統服務,看結果是否符合預期,這部份就屬於人工測試的範圍。

為什麼要寫測試?

  1. 確保程式碼品質。每次改動某個功能、模組,時常會忽略、擔心會不會導致別的呼叫端錯誤,只要有單元測試就可以避免這個問題,每次改版完都只要跑一次測試並且都通過,就可以確保改動後的邏輯是沒問題的、不會牽連到其他模組。

  2. 省去人工測試麻煩。雖然寫單元測試需要額外花時間,但只要寫完一次就可以不斷重複使用,也省去自己 Debug 跑模擬的過程。

  3. 彈性高。可以一上班就測試、中午測試、下班測試、上版時搭配 CI/CD 自動測試,想什麼時候測試都可以。

  4. 速度快。單元測試的執行速度應該要非常快,所以跑測試也就不需要太多時間。

如何建立測試專案

建議將測試程式碼獨立開一個專案來存放,避免混亂。

在 Visual Studio 中,直接新增專案就有範本了,可以看到包含 .NET Core 與 .NET Framework。其中.NET Core 已經有 MSTest、NUnit、xUnit 的範本。

檔名規範

可自訂。若沒有想法的話可在要測試的 cs 檔後面加上 Tests

路徑規範

與原本專案一致即可

e.g.

專案/Service/Service.cs

測試專案/Service/ServiceTests.cs

MSTest

這是微軟官方自己出的測試框架,但有鑑於我在網路上查資料用這套的人好像不多,因此就不特別介紹語法怎麼寫。

NUnit

寫測試程式

在測試專案安裝 NuGet 套件 NUnit,於測試專案底下加入一個測試檔案 Tests.cs

其中 [TestFixture] 指出這個 Class 是測試用的 Class

而 [Test] 則代表此 Method 是測試 Method,如果不寫 [Test] 則測試時就不會跑。

執行測試

開啟 Test Explorer :上方工具列 > 測試 > Test Explorer (或是快捷鍵 Ctrl + E, T)

因為沒有任何程式碼,所以執行測試後通過。

驗證 (Assert)

Assert 語法就是寫單元測試中的關鍵了,用以判斷實際得到的結果與預期的結果是否相符。若 Assert 是 True,則測試會通過。

改善程式碼

Method命名方式

這點其實沒有一定,選用適合自己團隊都能接受的方法就好。如果沒有想法,可以參考微軟的 Best Practice

這裡就以這篇文章的原則來介紹。

測試的名稱應該包含三個部分

  • 所測試的方法名稱

  • 用以測試的案例

  • 叫用案例時的預期行為

測試方法名稱_測試案例_預期行為

將 MyTest 更名為 Add_InputTwoInreger_ReturnSum

以 3A 原則改善程式碼

Arrange: 初始化

Act: 執行方法、行為、操作並取得結果

Assert: 驗證

這三個步驟會讓測試更明確,同時也應該加入註解中。

測試多筆資料

使測資放在傳入參數中,用 [TestCase] 即可

也可以使用 TestCaseSource 的方式,從外部代入測試資料,這樣的話就可以將測試資料額外放一個檔案

e.g.

TestCases\TestCases.cs

其中回傳的測試資料型態為 TestCaseData 的集合,這種方式可以輕易代入參數、並且設定測試的名稱。

SetUp 與 TearDown

SetUp: 每個測試案例開始前,會執行此方法。通常用來還原測試案例初始化狀態,確保測試案例不互相干擾。

TearDown: 每個測試案例完成後,會執行此方法。通常用來清除測試案例的狀態,確保測試案例不互相干擾。

執行順序如下:

SetUp

Test1

TearDown

SetUp

Test2

TearDown

xUnit

標記測試方法

與 NUnit 不同,需標記為 [Fact]

xUnit 沒有標記為測試 Class 的方法,它會自動搜尋測試專案內的測試方法。實際上 NUnit 也可以省略標記測試 Class,至於這樣會不會為了搜尋而拖慢速度?這不清楚。

測試多筆資料

使用 [Theory] 與 [InlineData] 達成

若要將測試資料額外分開,則使用 [MemberData] (另外也有 [ClassData] 的方法)

TestData 內提供 2 種給予測資的方式 AddData 與 AddData2

目前查不到個別設定測試名稱的方式,只可統一使用 DisplayName 放在 [Theory]

Fact 與 Theory

*Facts* are tests which are always true. They test invariant conditions.

*Theories* are tests which are only true for a particular set of data.

Fact 只用於測試單一情況,不會有外在影響,因此也不可有傳入參數

Theory 用於測試特定資料,可有傳入參數

Constructor 與 Dispose

xUnit 沒有 NUnit 那樣的 SetUp 與 TearDown。

xUnit 認為這兩個方法是糟糕的方法,取而代之的 xUnit 是使用建構、解構的概念去實作。

Analyzers

xUnit 有 Analyzers 套件,可以自動分析測試程式碼的好壞。

去 NuGet 安裝 xunit.analyzers

範例 1

用 Assert.True 與 string.StartWith 判斷某 string 開頭是否為 “AB”,但 xUnit 有可讀性更佳的 Assert.StartWith

範例 2

[Fact] 不可傳入參數,需用 [Theory] 或者刪除傳入參數

NUnit 與 xUnit 簡易比較

其實所有的測試框架都差不多,差異僅有一些特別功能,但感覺這些功能的使用時機也不多。

功能比較

語法差異

  1. xUnit 在 Assert 上捨去了 be 動詞 is, are

  • xUnit: Assert.Equal() Assert.Null()

  • NUnit: Assert.AreEqual() Assert.IsNull()

  • Exception 的處理

  • xUnit: Assert.Throws(() => Add(0, 1));

  • NUnit: Throws.TypeOf

xUnit 的 Assert.Throws<> 內部是接收一個 delegate,Assert.Throws(() => 物件.方法);

代表某物件的某方法應該要會 Throw 指定的 Exception

SetUp / TearDown 與 Constructor / Dispose

範例如下:

與其這樣寫,不如在每個測試都 new 出一個物件、賦予這個情境下的數值。雖然多了些重複的 code,但至少確保每個測試都是獨立且封閉的。

而 xUnit 則使用建構、解構的方式實作該功能,不會每個測試都重一次初始化、清除狀態。

而是 初始化 -> 跑完所有測試 -> 清除狀態

不過 NUnit 也沒有強制要寫 SetUp 與 TearDown。使用 NUnit 可以考慮避開 SetUp 與 TearDown

相依性

xUnit 在每個測試中分別使用新的 Instance,強迫每個測試都獨立、封閉,且相依性為 0,請看以下範例

NUnit

xUnit

擴展性

xUnit 可自定義 Attributes ,這是其他測試框架都沒有的功能。

文件

NUnit 較齊全,xUnit 連 Attributes 的說明文件都沒有。

Fluent Assertions

什麼是 Fluent Assertions

一種口語化的 Assert,讓程式碼更有可讀性,且跨測試框架,若有多種測試框架並行的情況,仍可用同一種 Assert 寫法。

基本上把測試結果講出來,Code 差不多就是那樣子寫。

安裝

去 NuGet 安裝 Fluent Assertions

範例

以 xUnit 為例,某 string 需要一次判斷 4 個條件

改成 Fluent Assertions

就是這麼簡單。

判斷物件是否相等

自定義物件是 Reference type,要比對裡面的值是否一樣需要自訂比較方法或是 Override Equal 方法,但 Fluent Assertions 只要一個方法即可搞定。

程式碼覆蓋率 (Code Coverage)

概述

代表程式碼被測試的比例。

以下要被測試的 Class 只有一個方法 Test,輸入什麼數字就回傳什麼數字。

測試方法這樣會傳入 1, 2, 3 ,共 3 個整數

註:Assert 與 Fluent Assertions 只要擇一來寫就好。這邊多寫是範例。

這樣子程式碼覆蓋率 (Code Coverage) 就是 75%,因為 5 個 case 中只測試了 3 個 case

分析工具

Visual Studio Enterprise (企業版)

Visual Studio Enterprise 內建就有程式碼覆蓋率的工具,且有 UI,讓操作與閱讀都十分方便。但只有企業版有這個功能。

dotCover

JetBrains 出品的工具,也是有 UI 的。但是是付費工具,有 30 天免費試用,或者該公司產品的 ReSharper 也有附贈。

那免費仔該怎麼辦呢?幸好他們有開放 Command line tools 免費使用,太棒啦

.NET Core

打開 CMD 視窗 > cd 到 dotCover 的目錄 > 輸入以下指令 (MSTest、NUnit、xUnit 都是同一個指令)

dotCover.exe dotnet — output=AppCoverageReport.html — reportType=HTML — test “C:\MyProject\MainTests.csproj”

參數說明

output: 輸出覆蓋率報告的位置、名字。若不指定輸出路徑,則輸出在 dotCover 目錄底下

output=C:\Users\Hao\Report\AppCoverageReport.html 指定路徑

reportType: 輸出覆蓋率報告的類型,這邊用 HTML

test: 要分析覆蓋率的測試專案,需指到 csproj 檔

如此一來就會在 dotCover 的目錄底下輸出一個 AppCoverageReport.html 檔,把它打開就可以看到覆蓋率的分析了。其中綠色代表有被測試到、紅色代表沒有被測試到。

分析包含了:該檔案的覆蓋率、檔案內的方法的覆蓋率等等……

.NET Framework

打開 CMD 視窗 -> cd 到 dotCover 的目錄 -> 輸入以下指令 (根據不同測試框架,參數值會不同)

dotcover cover /TargetExecutable=”TestRunner\TestRunner.exe” /TargetArguments=”C:\MyProject\bin\Debug\MyTest.dll” /Output=”AppCoverageReport.html” /ReportType=”HTML”

參數說明

TargetExecutable: 要執行的測試框架的 Runner

TargetArguments: 要被分析覆蓋率的測試專案,編譯後產出的 dll

Output: 輸出覆蓋率報告的位置、名字。若不指定輸出路徑,則輸出在 dotCover 目錄底下

ReportType: 輸出覆蓋率報告的類型,這邊用 HTML

MSTest

若顯示錯誤訊息,請嘗試使用「以系統管理員身分執行」來執行 CMD

dotcover cover /TargetExecutable=”C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\IDE\Extensions\TestPlatform\vstest.console.exe” /TargetArguments=”C:\MyProject\bin\Debug\MyTest.dll” /Output=”AppCoverageReport.html” /ReportType=”HTML”

如果要用 vstest.console 去執行測試,指令如下

vstest.console.exe myTestProject.dll

NUnit

先去 NuGet 安裝 NUnit.ConsoleRunner,然後 TargetExecutable 參數指定該套件底下的 nunit3-console.exe

dotcover cover /TargetExecutable=”~\nunit.consolerunner\3.11.1\tools\nunit3-console.exe” /TargetArguments=”C:\MyProject\bin\Debug\MyTest.dll” /Output=”AppCoverageReport.html” /ReportType=”HTML”

xUnit

先去 NuGet 安裝 xunit.runner.console,然後 TargetExecutable 參數指定該套件底下的 xunit.console.exe

目錄底下有很多資料夾細分對應的 .NET 版本

dotcover cover /TargetExecutable=”~\xunit.runner.console\2.4.1\tools\net472\xunit.console.exe” /TargetArguments=”C:\MyProject\bin\Debug\MyTest.dll” /Output=”AppCoverageReport.html” /ReportType=”HTML”

其他

Selenium

什麼是 Selenium

Selenium 是 E2E 測試工具,可執行開啟瀏覽器、操作功能等行為,可模擬使用者操作系統的真實情況。

安裝

去 NuGet 安裝 Selenium.WebDriver

若要測試某瀏覽器,需要額外安裝該瀏覽器的 WebDriver,以 Chrome 為例

範例

這是模擬使用 Google 搜尋引擎搜尋關鍵字 "Google" 是否成功

打開瀏覽器,並且測試結束時關閉

using (IWebDriver driver = new ChromeDriver())

設定一個監聽事件

WebDriverWait wait = new WebDriverWait(driver, TimeSpan.FromSeconds(10));

前往 Google 搜尋引擎網址

driver.Navigate().GoToUrl("https://www.google.com/");

根據 Name 找到填入關鍵字的欄位,並且使用 SendKeys() 填入關鍵字 "Google"

最後透過 Name 找到搜尋按鈕呼叫 Click() 按下。

driver.FindElement(By.Name("q")).SendKeys("Google");
driver.FindElement(By.Name("btnK")).Click();         

搜尋成功後,右方會出現關於 Google 的介紹,我以介紹上方的圖片(紅框處)有出現來當作搜尋已經完成。

而這張圖片資訊如下,找到能辨識它的資訊即可(紅框處)

wait.Until(ExpectedConditions.ElementExists(By.Id("wp_thbn_13")));

圖片出現後視為搜尋已完畢,我透過 Fluent Assertions 驗證網頁標題

driver.Title.Should().Be("Google - Google 搜尋");

跑這個測試 Selenium 會打開 Chrome 瀏覽器來實際做這些操作並且測試。

我以這一套流程以及 UI 的出現,來判定搜尋功能是正常可以運作的。

如何不實際開啟瀏覽器測試?

我們跑測試時剛開始也許需要實際看瀏覽器的操作來確保自己的程式碼正確。當確認完畢後,我們不希望每次測試都要打開瀏覽器,耗時又佔記憶體。

Chrome 有個 headless 模式,只要將這個參數傳入建構子,跑測試時就不會真的開啟瀏覽器測試。

ChromeOptions chromeOptions = new ChromeOptions();
chromeOptions.AddArguments("headless");
using (IWebDriver driver = new ChromeDriver(chromeOptions))
{
}

Selenium IDE

Selenium IDE 可以直接錄製你對網頁的操作、甚至轉成程式碼,在不懂程式的情況下仍可完成人工測試腳本。

以 Chrome 為例:

去擴充功能搜尋 Selenium IDE

打開 Selenium IDE

點選 Record a new test in a new project

輸入測試專案名稱,這可以協助你分類測試腳本

輸入想要錄製腳本的網址,按下 START RECORDING

Selenium IDE 會打開你輸入的網址,打開後就已經在錄製了,可以執行自己想測試的操作。

搜尋完畢後,我選擇依照網頁的標題來是否搜尋成功,在頁面 右鍵 > Selenium IDE > Assert > Title

點開 Selenium IDE,按下停止錄製就完成了。

左邊就是你所有的測試,右邊是該測試執行的動作,最後一個動作是 Assert Title 是否為 “Google — Google 搜尋”

執行測試後綠色代表成功。

如何匯出成程式碼

滑鼠移到測試名稱上,最右邊應該會顯示 3 個點

按下 Export

就可以將剛剛錄製的腳本轉成程式碼

參考資料

PreviousC# 集合, List<> 取交集、差集、聯集的方法NextCORS 介紹與設定方式

Last updated 6 months ago

更詳細的介紹請看

img

img
img
img

img
img
img
img
img
img

img
img
img
img

為什麼 xUnit 不使用像是 [Test] 這樣的標記?以下節錄至 :

img
img
img
img
img
img

太多了,請直接看這篇文章

xUnit 認為 SetUp 與 TearDown 是不好的方法。雖然 SetUp 與 TearDown 可以協助初始化、清除狀態,但是每個測試執行前後都會分別呼叫一次 SetUp 與 TearDown,如果在 SetUp 中不只是 new 出一個物件,甚至還賦值。在特殊案例的測試中又需要視情況賦值,如此一來特殊案例就重複賦值,且每一個測試都會需要一次掌管 3 個 Method:SetUp、自己、TearDown,這違反了 中的 。

img
img
img
img

可參考

img
img
img
img
img
img

教學請看官方文件

去 下載 dotCover Command Line Tools

img
img
img
img

其他還有 、 等,但似乎都只針對 .NET Core 使用。且這兩個工具產出的覆蓋率報告是 XML 格式,需透過 來將報告轉為 HTML 格式。

img
img
img
img
img
img
img
img
img
img
img
img
img
img
img

[Creating parameterised tests in xUnit with

一次搞懂單元測試、整合測試、端對端測試之間的差異
MSTest 官方介紹
NUnit 官方網站
單元測試最佳做法
xUnit 官方網站
官方說明
MSTest,NUnit 3,xUnit.net 2.0 比較
SOLID
單一職責原則
Creating a custom xUnit theory test DataAttribute to load data from JSON files
Fluent Assertions 官方網站
使用程式碼涵蓋範圍來決定所測試的程式碼數量
官方網站
OpenCover
Coverlet
ReportGenerator
Selenium 官方網站
一次搞懂單元測試、整合測試、端對端測試之間的差異
NUnit — 測試案例 TestCaseSourceAttribute
.NET Core 和 .NET Standard 的單元測試最佳做法
InlineData], [ClassData], and [MemberData]
xUnit Theory: Working With InlineData, MemberData, ClassData
MSTest,NUnit 3,xUnit.net 2.0 比較
Comparing xUnit.net to other frameworks
Why you should not use SetUp and TearDown in NUnit
使用程式碼涵蓋範圍來決定所測試的程式碼數量
Coverage Analysis from the Command Line
VSTest.Console.exe 命令列選項
Why Should You Use xUnit? A Unit Testing Framework For .Net
Creating a custom xUnit theory test DataAttribute to load data from JSON files