ASP.NET Core 中做集成测试的三种方案
學習·進步
老張的哲學
不定期更新的
日常
? 在平時的開發中,我們很少會關注到測試的問題,更別說集成測試了,除非是公司有硬性要求或者是自己的開源項目中,為了整體架構的完整性,需要用測試來做輔助點綴,而更多的也僅僅是單元測試(說的就是我自己????),最近在寫書的時候才進一步考慮到這一點,如何在一個ASP.NET Core框架中,引入集成測試呢?
??這里我結合這三年開源的經驗,總結了一些心得,給大家分享一下,如果有更好的建議,歡迎在評論區進行留言喲。
PS:單元測試就不說了,比較簡單,最多就是依賴注入和MOCK的問題,不會的話也可以留言。
方案一:萬物皆可Mock
? 在軟件測試當中,我們經常,甚至是到處都會用到mock來處理對象實例化的問題,在單元測試中,mock十分常見,畢竟是為了測試一個小模塊,其他的就不需要考慮,直接mock就行了,如果在集成測試的時候,如何測試接口呢,比如BlogController如何使用?我在blog.core項目中,就是這么使用到的,示例代碼如下:
Mock<IBlogArticleServices> mockBlogSev = new Mock<IBlogArticleServices>();Mock<ILogger<BlogController>> mockLogger = new Mock<ILogger<BlogController>>();BlogController blogController;private IBlogArticleServices blogArticleServices;DI_Test dI_Test = new DI_Test();public BlogController_Should(){mockBlogSev.Setup(r => r.Query());var container = dI_Test.DICollections();blogArticleServices = container.Resolve<IBlogArticleServices>();blogController = new BlogController(mockLogger.Object);}? 說句實話,這并非是集成測試,這種寫法可能比較低端,通過mock配合new,創建了控制器,然后調用接口,看起來不是很高大上,而且集成測試本來就是要測試整體性,不能把所有的參數都mock吧。同時官方好像也說過,不要到處使用mock。
而且,這種方案,也要考慮如何使用依賴注入的問題!
所以這種方案做集成測試我給:
??
方案二:實例化TestServer對象
? 這種是比較常見的,也是微軟官方架構項目eShopOnContainers的推薦方案,簡單來說,就是微軟提供了一個TestSever的類,為我們提供一個類似WebHost的宿主服務器,只不過是測試服務器,那如何測試Controller控制器呢,示例代碼如下:
public TestServer CreateServer(){var path = Assembly.GetAssembly(typeof(CatalogScenariosBase)).Location;var hostBuilder = new WebHostBuilder().UseContentRoot(Path.GetDirectoryName(path)).ConfigureAppConfiguration(cb =>{cb.AddJsonFile("appsettings.json", optional: false).AddEnvironmentVariables();}).UseStartup<Startup>();var testServer = new TestServer(hostBuilder);testServer.Host.MigrateDbContext<CatalogContext>((context, services) =>{var env = services.GetService<IWebHostEnvironment>();var settings = services.GetService<IOptions<CatalogSettings>>();var logger = services.GetService<ILogger<CatalogContextSeed>>();new CatalogContextSeed().SeedAsync(context, env, settings, logger).Wait();}).MigrateDbContext<IntegrationEventLogContext>((_, __) => { });return testServer;}? 可以看到,通過new TestServer()的方式,生成一個服務器,就可以發起請求了,核心的還是我們的WebHostBuilder。
至于如何調用就更簡單了,直接對server發起HttpClient請求即可:
? 這種是很簡單的,而且也不用考慮mock的問題,畢竟用的直接就是web項目的WebHost宿主機Builder來構建的。
? 但是有一個很致命的問題,我們在.NET5以后,使用Autofac做依賴注入的容器,而且ConfigureServices也是沒有返回值的,這樣在使用上面的TestServer,就會報錯,提示找不到Autofac服務。
? 但是如果你查看eShopOnContainers的源碼后,就知道他們還是將ConfigureServices做了返回值處理:
public IServiceProvider ConfigureServices(IServiceCollection servic{// 自定義服務擴展services.AddAppInsight(Configuration)// and so on....AddCustomMVC(Configuration);// 使用Autofac依賴注入容器var container = new ContainerBuilder();container.Populate(services);return new AutofacServiceProvider(container.Build());}? 如果你能接受這種依賴注入的方式的話,也是可以使用這種方案的,這是一個注意點,要知道。
所以這種方案做集成測試我給:
????
方案三:使用.UseTestServer()
? 除了上面的這種方式,還有一種方式,也是官方提供的,比較類似,也是通過創建宿主機服務器的形式,不過是新的HostBuilder的ConfigureWebHostDefaults方式創建的,示例代碼如下:
public static IHostBuilder GetTestHost() {return new HostBuilder()//替換autofac作為DI容器.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureWebHostDefaults(webBuilder =>{webBuilder.UseTestServer().UseStartup<Startup>();}).ConfigureAppConfiguration((host, builder) =>{builder.SetBasePath(Directory.GetCurrentDirectory());builder.AddJsonFile("appsettings.json", optional: true);builder.AddEnvironmentVariables();}); }? 既然上面說了我們不能單獨處理自定義容器,我們就和之前一樣,指定就好,設計思路和我們的WebApi中的Program.cs特別像,然后使用起來就更加簡單了:
using var server = await ArticleScenariosBase.GetTestHost().StartAsync();// Action 發起接口請求var response = await server.GetTestClientWithToken().GetAsync("/api/blogs?page=1&pageSize=5");// Assert 確保接口狀態碼是200response.EnsureSuccessStatusCode();? 這種方案不僅兼容了第二種方案的優點,而且對之前我們設計的Autofac依賴注入容器沒有做任何的修改。
所以這種方案做集成測試我給:
?????
編者按:Blog.Core開源三周年
【原料】
?個人開源項目Blog.Core馬上就已經開源三周年了,經過許許多多的小伙伴功能努力的結果,希望給ASP.NET Core在國內的推廣,提供一個落地級別的案例。
【制法】
?A、累計提交上千次Commit;
?B、配合前、后、認證、鑒權一體化方案;
?C、不完全統計,被60+公司使用中;
【調味】
1.希望更多的小伙伴參與并提交PR。
2.希望更多的公司和組織使用,提供寶貴生產意見。
3.希望可以得到組織的孵化,讓項目更進一步,有意者可以聯系我。
Tips: 九月新內容,敬請期待。
HAPPY EVEY DAY!
總結
以上是生活随笔為你收集整理的ASP.NET Core 中做集成测试的三种方案的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 中国唯一一位女性 Apache Memb
- 下一篇: 使用 Blazor 开发内部后台(二):