有時候寫到 WebService 的單元測試時,需要注入 IConfiguration 時該怎麼處理? 想要使用單元測試專用的 appsettings.json 要怎麼讀取? 甚至要注入 IOptions 時又要怎麼處理? 這篇文章就來告訴你該怎麼做。
前置作業 首先先在測試專案建立一個 appsettings.Test.json,命名可以依照需求改變,裡面的內容依照需求自行加入,或者直接把 WebService 專案裡的 appsettings.json 整個複製過來再改內容。
然後將它的 CopyToOutputDirectory
設為 Alaways
。這點很重要,不然這個檔案不會出現在編譯後的資料夾中,執行時找不到檔案會報錯。
appsettings.Test.json
1 2 3 4 5 6 7 8 { "MySection" : "FooBar" , "YourSettingKey" : "MyValue" , "MyObject" : { "Foo" : "Bar" , "Sample" : "Text" } }
指定 appsettings 接下來再建立一個 AppSettingProvider.cs
,主要提供 Appsettings 的內容。
AppSettingProvider.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 using System.IO;using Microsoft.Extensions.Configuration;namespace WebApiTests.TestUtilities ;public static class AppSettingProvider { public static IConfiguration GetTestAppSettings () { var pah = Path.Combine("Settings" , "appsettings.Test.json" ); var builder = new ConfigurationBuilder().AddJsonFile(pah); var config = builder.Build(); return config; } public static IConfiguration GetTestAppSettings () { var pah = Path.Combine("Settings" , "appsettings.Development.json" ); var builder = new ConfigurationBuilder().AddJsonFile(pah); var config = builder.Build(); return config; } }
之後就可以在測試中指定設定檔和直接使用 IConfiguration。
ControllerTests.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ControllerTests { privare readonly IConfiguration _config; public ControllerTests () { _config = AppSettingProvider.GetTestAppSettings(); } [Fact ] public void GetMySection_從appsettings取值_應回傳FooBar() { var expected = "FooBar" ; var actual = _config.GetValue<string >("MySection" ); Assert.Contains(expected, actual); } }
IOptions 接下來我們來看,測試遇到使用 IOptions 時該如何處理。
先來看看我們的 OptionsModel。
MyObjectOptions.cs
1 2 3 4 5 6 7 8 public class MyObjectOptions { public static readonly string SectionName = "MyObject" ; public string Foo { get ; set ; } public string Sample { get ; set ; } }
看來是要指定一個名為 MyObject
的 section。那就來建立一個 AppSettingProvider 提供一下。
AppSettingProvider.cs
1 2 3 4 5 6 7 8 9 10 11 12 public static class AppSettingProvider { public static IOptions<MyObjectOptions> GetMyObjectOptions () { var testAppSettings = Path.Combine("Settings" , "appsettings.Test.json" ); var builder = new ConfigurationBuilder().AddJsonFile(testAppSettings); var config = builder.Build(); var options = Options.Create(config.GetSection(MyObjectOptions.SectionName).Get<MyObjectOptions>()); return options; } }
之後就可以在測試中直接使用 IOptions 了。
ControllerTests.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class ControllerTests { privare readonly IOptions<MyObjectOptions> _options; public ControllerTests () { _options = AppSettingProvider.GetMyObjectOptions(); } [Fact ] public void GetSample_從appsettings取值_應回傳Text() { var expected = "Text" ; var actual = _options.Value.Sample; Assert.Contains(expected, actual); } }
總結 其實就只是由 DI 操作改為手動載入,IOptions 的話沒有變。
在寫 dotnet core 的時候還是別忘了 IConfiguration 的操作,還有 IOptions 的運用。不然到時候像我一樣突然要手動載入就措手不及,開始 Google 個半天了。
參考 Populate IConfiguration for unit tests - stackoverflow
.NET Core Unit Testing - Mock IOptions - stackoverflow