最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

淺談.Net Core后端單元測試的實(shí)現(xiàn)

 更新時間:2021年03月09日 10:08:55   作者:寶樹吶  
這篇文章主要介紹了淺談.Net Core后端單元測試的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

1. 前言

單元測試一直都是"好處大家都知道很多,但是因?yàn)榉N種原因沒有實(shí)施起來"的一個老大難問題。具體是否應(yīng)該落地單元測試,以及落地的程度, 每個項(xiàng)目都有自己的情況。

本篇為個人認(rèn)為"如何更好地寫單元測試", 即更加 偏向?qū)嵺`向 中夾雜一些理論的分享。

下列示例的單元測試框架為 xUnit , Mock庫為 Moq

2. 為什么需要單元測試

優(yōu)點(diǎn)有很多, 這里提兩點(diǎn)我個人認(rèn)為的很明顯的好處

2.1 防止回歸

通常在進(jìn)行新功能/模塊的開發(fā)或者是重構(gòu)的時候,測試會進(jìn)行回歸測試原有的已存在的功能,以驗(yàn)證以前實(shí)現(xiàn)的功能是否仍能按預(yù)期運(yùn)行。

使用單元測試,可在每次生成后,甚至在更改一行代碼后重新運(yùn)行整套測試, 從而可以很大程度減少回歸缺陷。

2.2 減少代碼耦合

當(dāng)代碼緊密耦合或者一個方法過長的時候,編寫單元測試會變得很困難。當(dāng)不去做單元測試的時候,可能代碼的耦合不會給人感覺那么明顯。為代碼編寫測試會自然地解耦代碼,變相提高代碼質(zhì)量和可維護(hù)性。

3. 基本原則和規(guī)范

 3.1 3A原則

3A分別是"arrange、act、assert", 分別代表一個合格的單元測試方法的三個階段

  • 事先的準(zhǔn)備
  • 測試方法的實(shí)際調(diào)用
  • 針對返回值的斷言

一個單元測試方法可讀性是編寫測試時最重要的方面之一。 在測試中分離這些操作會明確地突出顯示調(diào)用代碼所需的依賴項(xiàng)、調(diào)用代碼的方式以及嘗試斷言的內(nèi)容.

所以在進(jìn)行單元測試的編寫的時候, 請使用注釋標(biāo)記出3A的各個階段的, 如下示例

[Fact]
public async Task VisitDataCompressExport_ShouldReturnEmptyResult_WhenFileTokenDoesNotExist()
{
  // arrange
  var mockFiletokenStore = new Mock<IFileTokenStore>();
  mockFiletokenStore
    .Setup(it => it.Get(It.IsAny<string>()))
    .Returns(string.Empty);

  var controller = new StatController(
    mockFiletokenStore.Object,
    null);

  // act
  var actual = await controller.VisitDataCompressExport("faketoken");

  // assert
  Assert.IsType<EmptyResult>(actual);
}

3.2 盡量避免直接測試私有方法

盡管私有方法可以通過反射進(jìn)行直接測試,但是在大多數(shù)情況下,不需要直接測試私有的private方法, 而是通過測試公共public方法來驗(yàn)證私有的private方法。

可以這樣認(rèn)為:private方法永遠(yuǎn)不會孤立存在。更應(yīng)該關(guān)心的是調(diào)用private方法的public方法的最終結(jié)果。

3.3 重構(gòu)原則

如果一個類/方法,有很多的外部依賴,造成單元測試的編寫困難。那么應(yīng)該考慮當(dāng)前的設(shè)計(jì)和依賴項(xiàng)是否合理。是否有部分可以存在解耦的可能性。選擇性重構(gòu)原有的方法,而不是硬著頭皮寫下去.

3.4 避免多個斷言

如果一個測試方法存在多個斷言,可能會出現(xiàn)某一個或幾個斷言失敗導(dǎo)致整個方法失敗。這樣不能從根本上知道是了解測試失敗的原因。

所以一般有兩種解決方案

  • 拆分成多個測試方法
  • 使用參數(shù)化測試, 如下示例
[Theory]
[InlineData(null)]
[InlineData("a")]
public void Add_InputNullOrAlphabetic_ThrowsArgumentException(string input)
{
  // arrange
  var stringCalculator = new StringCalculator();

  // act
  Action actual = () => stringCalculator.Add(input);

  // assert
  Assert.Throws<ArgumentException>(actual);
}

當(dāng)然如果是對對象進(jìn)行斷言, 可能會對對象的多個屬性都有斷言。此為例外。

3.5 文件和方法命名規(guī)范 文件名規(guī)范

一般有兩種。比如針對 UserController 下方法的單元測試應(yīng)該統(tǒng)一放在 UserControllerTest 或者 UserController_Test

單元測試方法名

單元測試的方法名應(yīng)該具有可讀性,讓整個測試方法在不需要注釋說明的情況下可以被讀懂。格式應(yīng)該類似遵守如下

<被測試方法全名>_<期望的結(jié)果>_<給予的條件>

// 例子
[Fact]
public void Add_InputNullOrAlphabetic_ThrowsArgumentException()
{
 ...
}

4. 常用類庫介紹

4.1 xUnit/MsTest/NUnit

編寫.Net Core的單元測試?yán)@不過要選擇一個單元測試的框架, 三大單元測試框架中

  • MsTest是微軟官方出品的一個測試框架
  • NUnit沒用過
  • xUnit是.Net Foundation下的一個開源項(xiàng)目,并且被dotnet github上很多倉庫(包括runtime)使用的單元測試框架

三大測試框架發(fā)展至今已是大差不差, 很多時候選擇只是靠個人的喜好。

個人偏好 xUnit 簡潔的斷言

// xUnit
Assert.True()
Assert.Equal()

// MsTest
Assert.IsTrue()
Assert.AreEqual()

客觀地功能性地分析三大框架地差異可以參考如下

https://anarsolutions.com/automated-unit-testing-tools-comparison

4.2 Moq

官方倉庫

https://github.com/moq/moq4

Moq是一個非常流行的模擬庫, 只要有一個接口它就可以動態(tài)生成一個對象, 底層使用的是Castle的動態(tài)代理功能.

基本用法

在實(shí)際使用中可能會有如下場景

public class UserController
{
  private readonly IUserService _userService;
  
  public UserController(IUserService userService)
  {
    _userService = userService;
  }
  
  [HttpGet("{id}")]
  public IActionResult GetUser(int id)
  {
    var user = _userService.GetUser(id);
    
    if (user == null)
    {
      return NotFound();
    }
    else
    {
      ...
    }
  }
}

在進(jìn)行單元測試的時候, 可以使用 Moq_userService.GetUser 進(jìn)行模擬返回值

[Fact]
public void GetUser_ShouldReturnNotFound_WhenCannotFoundUser()
{
  // arrange
  // 新建一個IUserService的mock對象
  var mockUserService = new Mock<IUserService>();
  // 使用moq對IUserService的GetUs方法進(jìn)行mock: 當(dāng)入?yún)?33時返回null
  mockUserService
   .Setup(it => it.GetUser(233))
   .Return((User)null);
  var controller = new UserController(mockUserService.Object);
  
  // act
  var actual = controller.GetUser(233) as NotFoundResult;
  
  // assert
  // 驗(yàn)證調(diào)用過userService的GetUser方法一次,且入?yún)?33
  mockUserService.Verify(it => it.GetUser(233), Times.AtMostOnce());
}

4.3 AutoFixture

官方倉庫

https://github.com/AutoFixture/AutoFixture

AutoFixture是一個假數(shù)據(jù)填充庫,旨在最小化3A中的 arrange 階段,使開發(fā)人員更容易創(chuàng)建包含測試數(shù)據(jù)的對象,從而可以更專注與測試用例的設(shè)計(jì)本身。

基本用法

直接使用如下的方式創(chuàng)建強(qiáng)類型的假數(shù)據(jù)

[Fact]
public void IntroductoryTest()
{
  // arrange
  Fixture fixture = new Fixture();

  int expectedNumber = fixture.Create<int>();
  MyClass sut = fixture.Create<MyClass>();
  
  // act
  int result = sut.Echo(expectedNumber);
  
  // assert
  Assert.Equal(expectedNumber, result);
}

上述示例也可以和測試框架本身結(jié)合,比如xUnit

[Theory, AutoData]
public void IntroductoryTest(
  int expectedNumber, MyClass sut)
{
  // act
  int result = sut.Echo(expectedNumber);
  
  // assert
  Assert.Equal(expectedNumber, result);
}

5. 實(shí)踐中結(jié)合Visual Studio的使用

Visual Studio提供了完備的單元測試的支持,包括運(yùn)行. 編寫. 調(diào)試單元測試。以及查看單元測試覆蓋率等。

5.1 如何在Visual Studio中運(yùn)行單元測試

5.2 如何在Visual Studio中查看單元測試覆蓋率

如下功能需要Visual Studio 2019 Enterprise版本,社區(qū)版不帶這個功能。

如何查看覆蓋率

  • 在測試窗口下,右鍵相應(yīng)的測試組 點(diǎn)
  • 點(diǎn)擊如下的"分析代碼覆蓋率"

6. 實(shí)踐中常見場景的Mock

主要

6.1 DbSet

使用EF Core過程中,如何mock DbSet是一個繞不過的坎。

方法一

參考如下鏈接的回答進(jìn)行自行封裝

https://stackoverflow.com/questions/31349351/how-to-add-an-item-to-a-mock-dbset-using-moq

方法二(推薦)

使用現(xiàn)成的庫(也是基于上面的方式封裝好的)

倉庫地址:

https://github.com/romantitov/MockQueryable

使用范例

// 1. 測試時創(chuàng)建一個模擬的List<T>
var users = new List<UserEntity>()
{
 new UserEntity{LastName = "ExistLastName", DateOfBirth = DateTime.Parse("01/20/2012")},
 ...
};

// 2. 通過擴(kuò)展方法轉(zhuǎn)換成DbSet<UserEntity>
var mockUsers = users.AsQueryable().BuildMock();

// 3. 賦值給給mock的DbContext中的Users屬性
var mockDbContext = new Mock<DbContext>();
mockDbContext
 .Setup(it => it.Users)
 .Return(mockUsers);

6.2 HttpClient

使用RestEase/Refit的場景

如果使用的是 RestEase 或者 Refit 等第三方庫,具體接口的定義本質(zhì)上就是一個interface,所以直接使用moq進(jìn)行方法mock即可。

并且建議使用這種方式。

IHttpClientFactory

如果使用的是.Net Core自帶的 IHttpClientFactory 方式來請求外部接口的話,可以參考如下的方式對 IHttpClientFactory 進(jìn)行mock

https://www.thecodebuzz.com/unit-test-mock-httpclientfactory-moq-net-core/

6.3 ILogger

由于ILogger的LogError等方法都是屬于擴(kuò)展方法,所以不需要特別的進(jìn)行方法級別的mock。

針對平時的一些使用場景封裝了一個幫助類, 可以使用如下的幫助類進(jìn)行Mock和Verify

public static class LoggerHelper
{
  public static Mock<ILogger<T>> LoggerMock<T>() where T : class
  {
    return new Mock<ILogger<T>>();
  }

  public static void VerifyLog<T>(this Mock<ILogger<T>> loggerMock, LogLevel level, string containMessage, Times times)
  {
    loggerMock.Verify(
    x => x.Log(
      level,
      It.IsAny<EventId>(),
      It.Is<It.IsAnyType>((o, t) => o.ToString().Contains(containMessage)),
      It.IsAny<Exception>(),
      (Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
    times);
  }

  public static void VerifyLog<T>(this Mock<ILogger<T>> loggerMock, LogLevel level, Times times)
  {
    loggerMock.Verify(
    x => x.Log(
      level,
      It.IsAny<EventId>(),
      It.IsAny<It.IsAnyType>(),
      It.IsAny<Exception>(),
      (Func<It.IsAnyType, Exception, string>)It.IsAny<object>()),
    times);
  }
}

使用方法

[Fact]
public void Echo_ShouldLogInformation()
{
  // arrange
  var mockLogger = LoggerHelpe.LoggerMock<UserController>();
  var controller = new UserController(mockLogger.Object);
  
  // act
  controller.Echo();
  
  // assert
  mockLogger.VerifyLog(LogLevel.Information, "hello", Times.Once());
}

7. 拓展

7.1 TDD介紹

TDD是測試驅(qū)動開發(fā)(Test-Driven Development)的英文簡稱. 一般是先提前設(shè)計(jì)好單元測試的各種場景再進(jìn)行真實(shí)業(yè)務(wù)代碼的編寫,編織安全網(wǎng)以便將Bug扼殺在在搖籃狀態(tài)。

此種開發(fā)模式以測試先行,對開發(fā)團(tuán)隊(duì)的要求較高, 落地可能會存在很多實(shí)際困難。詳細(xì)說明可以參考如下

https://www.guru99.com/test-driven-development.html

參考鏈接

https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices

https://www.kiltandcode.com/2019/06/16/best-practices-for-writing-unit-tests-in-csharp-for-bulletproof-code/

https://github.com/AutoFixture/AutoFixture

到此這篇關(guān)于淺談.Net Core后端單元測試的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān).Net Core 單元測試內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論

安义县| 惠来县| 柳林县| 红安县| 抚顺县| 张家界市| 卓资县| 突泉县| 靖安县| 原平市| 河源市| 西吉县| 富平县| 铁岭县| 柘城县| 临泽县| 祁门县| 定边县| 江源县| 信宜市| 来宾市| 镇安县| 彩票| 山阴县| 鄂伦春自治旗| 抚宁县| 改则县| 马鞍山市| 和田市| 闽侯县| 临武县| 乌拉特后旗| 湖口县| 闽清县| 宝鸡市| 永丰县| 陇南市| 兴山县| 竹溪县| 仁寿县| 宁陕县|