單元測試 Unit Test (三) ─ Validation | 驗證 Web API 的 Request | Fluent Validation

本篇會做 Web API 的 Request 驗證。

FluentValidaiton ( NuGet 套件 ),在 Visual Studio 用 C# 寫範例程式碼。

之前單元測試Unit Test (二)─實例撰寫過程─面積計算功能是用 FluentAssertions ( NuGet 套件 )。

上一篇設計完 Web API 的規格,這篇開始依照規格寫 API。

用 POST 方法建立同業合作契約 (Cobroke Letter) 的API,範例程式碼如下

[HttpPost]
public IActionResult CreateCobrokeLetter(CreateCobrokeLetterRequest request)
{

    //---本篇重點要講的驗證---
    var validator = new CreateCobrokeLetterRequestValidator();
    var validationResult = validator.Validate(request);
    if (!validationResult.IsValid)
    {
        return BadRequest(validationResult.Errors);
    }

    //---本篇重點要講的驗證---

    var cobrokeLetterId = _cobrokeLetterService.CreateCobrokeLetter(request);

    var response = new CreateCobrokeLetterResponse()
    {
        Message = $"Successfully Create Cobroke Letter Id = {cobrokeLetterId}."
    };

    //return Ok(response);
    return CreatedAtAction(nameof(GetCobrokeLetter), new { id = cobrokeLetterId }, response);
}

我們要驗證使用者給的 Request 是不是有符合API的設計,防止API因為不合的Request而爆炸

因此我們要驗證 (Validation) 抓出因為不合的Request造成的錯誤,並丟出錯誤訊息提醒使用者哪裡錯了

步驟一、加入專案

  • 加入專案 ─ ASP.NET Core Web API。
    Visual Studio 會自動幫我們建立Controller、http檔。
    →要用來寫API Http方法
    e.g.,檔名:Esign.Api
     
  • 加入專案 ─ MSTest測試專案
    →用來寫API Request的validation單元測試,撰寫過程寫好的Production Code會放在Service層。
    e.g.,檔名:Esign.Service
     
  • 加入專案 ─ 類別庫
    →作為Service層,用來放Production Code。
    e.g.,檔名:Esign.Service.Test

並加入【專案參考】:

  • Esign.Service.Test 參考 Esign.Service
  • Esign.Api 參考 Esign.Service

步驟二、下載FluentValidation套件

FluentValidation 可以幫我們將 API 傳入的參數的檢查用更口語、更乾淨的方式去處理

除了可以將檢查邏輯拆分成單獨的 Validator 類別,更提供了許多內建的檢查規則和自訂的彈性,相當方便。

並且因為將參數的檢查邏輯整理出去,就可以和 Controller 本身的工作做簡單的拆分,達到關注點分離的目標。

步驟三、依照 Web API Spec 寫 Request 的 Validation 單元測試

輸入testc按兩下tab鍵,IDE自動建立TestClass

輸入testm按兩下tab鍵,IDE自動建立TestMethod

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
    }
}

先寫情境一、驗證建立契據人編號必為6碼

/// <summary>
/// 建立同業合作契約請求參數驗證測試
/// </summary>
[TestClass]
public class CreateCobrokeLetterRequestValidateTests
{
    /// <summary>
    /// 情境一、驗證建立契據人編號必為6碼
    /// </summary>
    [TestMethod]
    public void CreatedUserId_Not_Six_Number_Is_Invalid()
    {
        // Arrange
        // 加入一個建立契據人編號不為6碼的請求
        var request = new CreateCobrokeLetterRequest
        {
            CreatedUserId = "12345"
        };
        // 建立驗證器
        var validator = new CreateCobrokeLetterRequestValidator();

        // Act 執行驗證
        var validateResult = validator.TestValidate(request);

        // Assert 驗證結果
        validateResult.ShouldHaveValidationErrorFor(x => x.CreatedUserId)
            .WithErrorMessage("CreatedUserId must be 6 digits in length.");
    }
}

CreateCobrokeLetterRequestValidator的 Validator 繼承 AbstractValidator<T>

using FluentValidation;

namespace Esigning.Service
{
    /// <summary>
    /// 建立同業合作契約請求參數驗證器
    /// </summary>
    public class CreateCobrokeLetterRequestValidator : AbstractValidator<CreateCobrokeLetterRequest>
    {
        /// <summary>
        /// 建構式
        /// </summary>
        public CreateCobrokeLetterRequestValidator()
        {
            //CreatedUserId長度不是6碼&沒有填寫就會出現錯誤訊息
            RuleFor(x => x.CreatedUserId).Length(6).WithMessage("CreatedUserId must be 6 digits in length.")
            .NotNull().NotEmpty().WithMessage("EmployeeNumber cannot be null and empty.");
        }
    }
}

.Length(6):會驗證Request的CreatedUserId參數長度必須是6。

.WithMessage("CreatedUserId must be 6 digits in length."):前面的條件如果不符合會出現錯誤訊息。

.NotNull().NotEmpty():會驗證CreatedUserId參數必填。

通過單元測試

步驟四、完成所有驗證規則後,寫進API

[HttpPost]
public IActionResult CreateCobrokeLetter([FromBody] CreateCobrokeLetterRequest request)
{
    //驗證請求參數
    var validator = new CreateCobrokeLetterRequestValidator();
    var validateResult = validator.Validate(request);

    if (!validateResult.IsValid)
    {
        return BadRequest(validateResult.Errors);
    }

    //TODO: 使用Service建立同業合作契約

    var response = new CreateCobrokeLetterResponse
    {
        Message = $"Successfully Create Cobroke Letter."
    };

    return Ok(response);
}
  1. 先實例化CreateCobrokeLetterRequestValidator
  2. 使用validator驗證request
  3. 驗證的結果通過就往下執行去建立同業合作契約
    驗證有問題就回傳BadRequest與Error Message

這樣就完成 Request 的驗證囉🥳

可以參考我的程式碼 https://github.com/LilyLin395135/EsignAPI.git


下方是上一篇 設計 Web API 規格文件 的範例,本篇用這個Post方法的Request示範Validation的寫法。 

資源路徑
URL
操作名稱
Action Name
HTTP Method說明請求參數
Request
回應
Response
/esigning/co-broke-lettersCreateCobrokeLetterPOST建立同業合作線上簽名契約createRequest找到這筆資料的URL, cobrokeLetterId, response

201 Created 已建立
400 Bad Request 錯誤的要求

POST  ~/esigning/cobroke-letters

功能:建立同業合作契約資料

Action Name:CreateCobrokeLetter

Request 請求參數:createRequest

Body 參數名稱是否必填資料類型說明
CreateDateVDateTime建立契據日期
CreateUserIdVstring建立契據人編號,6碼數字
ListingVstring1 (For Sale);2 (For Rent)。不是1就是2或1,2
AskingPrice decimal開價 (For Sale有選,AskingPrice欄位必填)
Rental decimal租金 (For Rent有選,Rental欄位必填)

用 CreateUserId 的規則示範。


參考

伊果的沒人看筆記本─使用 Fluent Validation 來驗證參數吧

謝謝觀看,此為新手的學習筆記整理,若有錯誤,煩請指正🙏