單元測試
前言
時隔多個月,終於抽空學習了點新知識,那麼這次來記錄一下C#怎麼進行單元測試,單元測試是做什麼的。
我相信大部分剛畢業的都很疑惑單元測試是幹什麼的?在小廠實習了6個月後,我發現每天除了寫CRUD就是寫CRUD,幾乎用不到單元測試。寫完一個功能直接上手去測,當然這只是我個人感受,僅供參考。
然後當我還在抱怨測試好煩的時候,大佬跟我說為什麼不用單元測試和整合測試,我這也是有苦說不出。要知道光學會理論知識,沒有實踐作為基礎,都是扯淡,入職這麼久還真沒用過單元測試,嚇得我趕緊去找資料學習。
那麼也是透過觀看B站某位Up主的影片,然後有點想法寫下這篇文章,雖然up主的主題是探究介面的作用和意義,但是影片中也講解了怎麼進行單元測試,所以對於介面理解不夠的可以去本文底部觀看影片學習。
那麼本篇文章就簡單的講解下C#中如何做單元測試,博主也是處於學習階段,有不對的地方歡迎指出改正。
單元測試簡述
單元測試(Unit Testing)是軟體開發中的一種測試方法,用於驗證程式碼中的最小可測試單元(通常是方法或函式)是否按照預期進行工作。這些單元通常是獨立於其他程式碼部分進行測試的,以確保其正確性和可靠性。
單元測試的主要作用:
- 確保每個單元能正確執行預期功能
- 能夠儘快找到Bug的具體位置
開始測試
本文以當前時間去返回早上好、中午好、晚上好來講解單元測試。
透過傳入不同的時間(邊界值)來確保程式碼能夠正確處理各種情況以及是否達到了預期的功能。
預期結果為:
- 早上好...
- 中午好...
- 晚上好..
專案搭建
主程式
首先需要建立一個控制檯專案,起名為UnitTesting
並安裝Microsoft.Extensions.DependencyInjection
包,管理IOC容器。
建立ITimeProvider
介面,並建立SystemTimeProvider
類去實現這個介面
public interface ITimeProvider
{
int GetHour();
}
//返回當前時間
public class SystemTimeProvider: ITimeProvider
{
public int GetHour()
{
return DateTime.Now.Hour;
}
}
建立GreetingService
類
public class GreetingService
{
private readonly ITimeProvider _timeProvider;
public GreetingService(ITimeProvider timeProvider)
{
_timeProvider = timeProvider;
}
/// <summary>
/// 透過當前時間來打返回問候語
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public string Greet(string name)
{
var hour = _timeProvider.GetHour();
return hour switch
{
< 12 => $"Good Morning,{name}",
< 18 => $"Good Afternoon,{name}",
_ => $"Good Evening,{name}"
};
}
}
Program.cs
使用IOC容器注入服務並呼叫Greet方法
using Microsoft.Extensions.DependencyInjection;
using UnitTesting.Services;
var container = new ServiceCollection();
container.AddSingleton<ITimeProvider,SystemTimeProvider>();
container.AddTransient<GreetingService>();
var services = container.BuildServiceProvider();
var greetingService = services.GetRequiredService<GreetingService>();
var greeting = greetingService.Greet("嗎嘍");
Console.WriteLine(greeting);
測試程式
用xUnit
模版建立單元測試,名為UnitTesting.Test
,並新增UnitTesting
專案引用,還需安裝Moq
包:
Moq包(全稱Mocking Objects in C#,簡稱Moq)是一個流行的模擬框架,其主要作用在於模擬和驗證物件的行為,以支援更加可靠和可重複的測試,簡單來講就是模擬建立物件。
回到GreetingService
類,這裡使用Rider提供的快捷方式建立測試類,當然也可以手動建立。如圖:
測試流程:
- Arrange:準備階段,建立
ITimeProvider
的模擬物件provider
,並指定時間引數且呼叫GetHour()
方法,使用這個模擬物件建立GreetingService
例項。 - Act:執行階段,呼叫
GreetingService
的Greet
方法 - Assert:斷言階段,驗證返回的訊息是否與預期的結果相同。
using JetBrains.Annotations;
using Moq;
using UnitTesting.Services;
namespace UnitTesting.Tes.Services;
[TestSubject(typeof(GreetingService))]
public class GreetingServiceTests
{
[Fact]
public void GreetReturnsMorningMessage()
{
// Arrange
var provider = new Mock<ITimeProvider>();
provider.Setup(x => x.GetHour()).Returns(10);
var service = new GreetingService(provider.Object);
// Act
var message = service.Greet("嗎嘍");
// Assert
Assert.Equal("Good Morning,嗎嘍", message);
}
[Fact]
public void GreetReturnsAfternoonMessage()
{
// Arrange
var provider = new Mock<ITimeProvider>();
provider.Setup(x => x.GetHour()).Returns(15);
var service = new GreetingService(provider.Object);
// Act
var message = service.Greet("嗎嘍");
// Assert
Assert.Equal("Good Afternoon,嗎嘍", message);
}
[Fact]
public void GreetReturnsEveningMessage()
{
// Arrange
var provider = new Mock<ITimeProvider>();
provider.Setup(x => x.GetHour()).Returns(20);
var service = new GreetingService(provider.Object);
// Act
var message = service.Greet("嗎嘍");
// Assert
Assert.Equal("Good Evening,嗎嘍", message);
}
}
效果截圖
主程式沒什麼好講的,透過當前時間返回問候語。
測試程式透過3個測試方法測試了3種情況,早上好、中午好、晚上好,並全部測試透過。
總結
本文講解了如何建立單元測試,並且透過單元測試來測試Greet方法,在傳入不同的時間引數的情況下,判斷是否滿足3種情況。
本文提到了IOC容器、依賴注入、Moq、xUnit等知識點。
參考連結
- 【從單元測試出發探討介面的作用及意義】 https://www.bilibili.com/video/BV1Ut421V7Sz/?share_source=copy_web&vd_source=fce337a51d11a67781404c67ec0b5084
- Asp-Net-Core學習筆記:單元測試和整合測試 - 程式設計實驗室 - 部落格園 (cnblogs.com) https://www.cnblogs.com/deali/p/17559685.html