NUnit Test Project Init

前言

前面已經有寫了幾篇關於解耦合,抽象行為等等概念的說明了.

而建置測試專案雖然已經做了第二次了,但發現兩次我都會忘記怎麼做,因此才特別寫了這篇初始化的文章出來

碰到問題

在.NET Core 開發的過程中,都知道有IServiceProvider和IConfiguration這兩個介面可以取得實例或是Config的配置

但正常情況下都被框架包好了,根本不用去考慮他怎麼做出來的.

但在測試的途中,框架不會知道你是否要使用,因此也不會自動幫你建立一個出來,導致我們需要自己來建立.

建立專案

由於我現在的開發環境是 Mac OS 因此這裡就只示範 VSCode & .NET CLI

dotnet new nunit -n {ProjectName}

如果是6版本以上的話,會自動建立using.cs

這個是GloableUsing的部分,如果有全域要使用的using的話可以考慮放到這裡

Nunit的介紹

正常來講在寫整合測試的時候,我們為了減少變因,因此都會做一次初始化以及完畢的行為

例如:初始化建立相依的物件(DB,Redis等等相關連線)

完畢的時候要刪除測試的資料等等行為

而在NUnit中的屬性則叫做Setup(初始) & TearDown(結束)

實際上寫出來會長得像這樣

  [SetUp]
  public void SetUp()
  {
    //初始化區塊
  }

  [TearDown]
  public void TearDown()
  {
    //測試完成後執行的區塊
  }

建立IServiceProvider & IConfiguration

建立方式其實沒有很困難,實際方式如下

  protected IServiceCollection _services;
  protected IServiceProvider _sp;
  protected IConfiguration _configuration;

  [SetUp]
  public void SetUp()
  {
    // 先建立新的ServiceCollection
    this._services = new ServiceCollection();
    // 使用檔案進行Config抓取
    var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.Test.json");
    this._configuration = configuration.Build();

    //add MongoDB
    var appSettingsSection_MongoDB = _configuration.GetSection("MongoDbConfig");
    var appSettingsMongoDB = appSettingsSection_MongoDB.Get<DbConfig>();
    this._services.AddScoped<IMongoStorage>(sp => { return new MongoStorage(appSettingsMongoDB); });
    this._services.AddSingleton<IMongoFileStorage>(sp => { return new MongoFileStorage(appSettingsMongoDB); });
    // 創建出ServiceProvider
    this._sp = _services.BuildServiceProvider();
  }

  [TearDown]
  public void TearDown()
  {
    IMongoStorage db = this._sp.GetRequiredService<IMongoStorage>();
    Assert.AreEqual("TestDB",db.GetDB().DatabaseNamespace.DatabaseName, "DB Name must be TestDB");
    BsonDocument empty = new BsonDocument();
    DeleteResult deleteResult;
    deleteResult = db.GetCollection<UserInfo>("UserInfo").DeleteMany(empty);
  }
}

當中比較需要特別注意的是 appsettings.Test.json 會需要在csproj裡面特別說明要輸出到輸出目錄,否則會抓不到Config導致報錯

  <ItemGroup>
    <None Update="appsettings.Test.json">
      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
  </ItemGroup>

而因為這些比較算是每個測試都會使用的Init 所以其實可以抽成一個BasicTestClass 後續有相關測試的Class可以直接繼承使用,就不用每個Class都寫一次了.

總結

測試其實不難,真正難的會是在開發過程中的設計,如何設計商業邏輯以及低耦合才是最困難的點.