.NET Core系列 :4 测试
2016.6.27 微軟已經(jīng)正式發(fā)布了.NET Core 1.0 RTM,但是工具鏈還是預(yù)覽版,同樣的大量的開源測試庫也都是至少發(fā)布了Alpha測試版支持.NET Core, 這篇文章?The State of .Net Core Testing Today?就將各個開源測試庫的目前進展進行了匯總。本文我們的目的是在我們構(gòu)建我們應(yīng)用程序的時候能夠進行測試,如何使用XUnit結(jié)合你可以通過為你的項目添加不同的測試用例NSubstitute進行單元測試,同時對整個項目進行集成測試。這次我們使用Visual Studio 2015 Update 3進行編寫 。xUnit.net是基于.NET Framework 的開源測試工具。通過xUnit.net可以針對C#/F#/VB.NET等進行單元測試。ASP.NET Core 更直接把以往的Visual Studio Unit Test Framework 說再見了,而直接使用上了xUnit.net,xUnit.net基于NUnit 。從網(wǎng)站或者官網(wǎng)上,你可以找到不少xUnit的優(yōu)點,與NUnit和其他測試框架相比有一下一些優(yōu)勢??
???????? 1)為每個測試方法產(chǎn)生一個對象實例
???????? 2)取消了[SetUp]和[TearDown]
???????? 3)取消了[ExpectedException]
???????? 4)類似于Aspect的功能
???????? 5)減少了自定義屬性(Attribute)的數(shù)目
???????? 6)采用泛型
???????? 7)匿名委托
???????? 8)可擴展的斷言
???????? 9)可擴展的測試方法
???????? 10)可擴展的測試類
???????? 了解更多關(guān)于xUnit.net可以參考這里(點擊打開鏈接[舍棄Nunit擁抱Xunit])。
?
使用xUnit.net 單元測試
?
首先我們類似于.NET Core系列 :3 、使用多個項目?創(chuàng)建一個解決方案testdemo,添加一個類庫項目叫做DotnetCoreLib,Library.cs 也替換為:
namespace DotnetCoreLib
{
??? public class Calculator
??? {
??????? public int Multi(int x, int y)
??????? {
??????????? return x * y;
??????? }
??? }
}
下面我們要創(chuàng)建一個針對DotnetCoreLib的測試項目,具體創(chuàng)建過程我們參照文章?https://github.com/dotnet/core-docs/tree/master/samples/core/getting-started/unit-testing-using-dotnet-test?,我們修改DotnetCoreLibTest 項目的project.json ,增加XUnit相關(guān)的nuget包引用,并修改部分配置。
?
?
還有我們設(shè)置Framework節(jié)點為 netcoreapp1.0, 依賴的xunit 和xunit.runner的包
"dependencies": {
??? "dotnet-test-xunit": "2.2.0-preview2-build1029",
??? "DotnetCoreLib": {
????? "version": "1.0.0-*",
????? "target": "project"
??? },
??? "xunit": "2.2.0-beta2-build3300",
??? "xunit.runner.console": "2.2.0-beta2-build3300"
? }
?
Calculator接下來就開始測試我們的類庫Calculator, 修改Class1.cs為CalculatorTest.cs ,
?
using DotnetCoreLib;
using Xunit;
?
namespace DotnetCoreLibTest
{
??? public class CalTest
??? {
??????? private readonly Calculator calculator;
??????? public CalTest()
??????? {
??????????? calculator = new Calculator();
??????? }
?
??????? [Fact]
??????? public void OneMutiOneIsOne()
??????? {
??????????? var result = calculator.Multi(1, 1);
??????????? Assert.Equal(1, result);
??????? }
?
??????? [Theory]
??????? [InlineData(-1)]
??????? [InlineData(0)]
??????? [InlineData(1)]
??????? public void ReturnValue(int value)
??????? {
??????????? var result = calculator.Multi(1,value);
??????????? Assert.Equal(result, value);
??????? }
??? }
}
?
上面的兩個測試,我們分別用了2個特性[Fact] 和[Theory], [Fact]屬性表示為一個方法的單個測試,[Theory]屬性表示執(zhí)行相同的代碼,但是有不同的輸入的參數(shù)的測試套件。[InlineData] 屬性可用于指定為這些輸入值。通過特性[Fact] 和[Theory],xUnit就理解了這是個測試方法,然后運行這個方法。在一個測試方法中,我們一般遵循包含三步驟的AAA模式:
Arrange:為測試準備
Act:運行SUT(實際測試的代碼)
Assert:校驗結(jié)果
下面我們運行dotnet test 就可以看到結(jié)果了。
C:\Users\geffz\Documents\Visual Studio 2015\Projects\TestDemo\DotnetCoreLibTest>dotnet test
Project DotnetCoreLib (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
Project DotnetCoreLibTest (.NETCoreApp,Version=v1.0) was previously compiled. Skipping compilation.
xUnit.net .NET CLI test runner (64-bit .NET Core win10-x64)
? Discovering: DotnetCoreLibTest
? Discovered:? DotnetCoreLibTest
? Starting:??? DotnetCoreLibTest
? Finished:??? DotnetCoreLibTest
=== TEST EXECUTION SUMMARY ===
?? DotnetCoreLibTest? Total: 4, Errors: 0, Failed: 0, Skipped: 0, Time: 0.206s
SUMMARY: Total: 1 targets, Passed: 1, Failed: 0.
?
上面的輸出我們知道已經(jīng)執(zhí)行了4個測試,都通過了,[Face]特性標(biāo)識表示固定輸入的測試用例,而[Theory]特性標(biāo)識表示可以指定多個輸入的測試用例,結(jié)合InlineData特性標(biāo)識使用。在上面的例子里,總共使用了三次InlineData特性標(biāo)識,每次設(shè)定的值都不同,在執(zhí)行單元測試時,設(shè)定的值會被測試框架賦值到對應(yīng)的測試方法的參數(shù)里。你可以通過為你的項目添加不同的測試用例,這樣就可以讓你的代碼得到充分測試。
?
xUnit.net 搭配NSubstitute?進行單元測試
?
?? 在一個分層結(jié)構(gòu)清晰的項目里,各層之間依賴于事先約定好的接口。在多人協(xié)作開發(fā)時,大多數(shù)人都只會負責(zé)自己的那一部分模塊功能,開發(fā)進度通常情況下也不一致。當(dāng)某個開發(fā)人員需要對自己的模塊進行單元測試而依賴的其他模塊還沒有開發(fā)完成時,則需要對依賴的接口通過Mock的方式提供模擬功能,從而達到在不實際依賴其他模塊的具體功能的情況下完成自己模塊的單元測試工作。這時我們通常需要有一個單元測試模擬類庫,一直以來,開發(fā)者對 mocking 類庫的語法的簡潔性有強烈的需求,NSubstitute 試圖滿足這一需求。簡單明了的語法可以讓我們將重心放在測試本身,而不是糾纏在測試替代實例的創(chuàng)建和配置上。NSubstitute 已嘗試將最常用的操作需求簡單化、易用化,并支持一些不常用的或探索性的功能,與此同時還盡可能地將其語法向自然語言靠近。關(guān)于NSubstitute的更詳細信息請往?NSubstitute完全手冊索引。
?
NSubstitute 已經(jīng)發(fā)布2.0 RC版本支持.NET Core。引入NSubstitute 相關(guān)nuget包:
我們把Calculator 類重構(gòu)下提取出接口ICalculator:
??? public interface ICalculator
??? {
??????? int Multi(int x, int y);
??? }
?
我們可以讓NSubstitute來創(chuàng)建類型實例的替代實例,可以創(chuàng)建諸如 Stub、Mock、Fake、Spy、Test Double 等,但當(dāng)我們只是想要一個能有一定程度控制的替代實例時,為什么我們要困擾于此呢?我們可以告訴被創(chuàng)建的替代實例,當(dāng)方法被調(diào)用時返回一個值:
???? [Fact]
????? public void Test_GetStarted_ReturnSpecifiedValue()
????? {
????????? ICalculator calculator = Substitute.For<ICalculator>();
????????? calculator.Multi(1, 2).Returns(2);
????????? int actual = calculator.Multi(1, 2);
????????? Assert.Equal(2, actual);
????? }
下面我們運行dotnet test 就可以看到結(jié)果了,增加了上面的2個用例,關(guān)于NSubstitute的更詳細信息請往?NSubstitute完全手冊索引。
?
集成測試
上面我們只是對邏輯進行了單元測試。對于Asp.Net Core項目,還需要模擬在網(wǎng)站部署的情況下對各個請求入口進行測試。NET Core 可為快速輕松集成測試提供非常棒的支持。
TestServer 類為 ASP.NET Core 中的集成測試執(zhí)行大部分繁重操作,Microsoft.AspNetCore.TestHost 包中具有此類。本節(jié)內(nèi)容來自于MSDN雜志《?ASP.NET Core - 實際的 ASP.NET Core MVC 篩選器》,這些集成測試不需要數(shù)據(jù)庫或 Internet 連接或運行的 Web 服務(wù)器。它們?nèi)缤瑔卧獪y試一樣快速簡單,但最重要的是,它們允許你在整個請求管道中測試 ASP.NET 應(yīng)用,而不只是控制器類中的孤立方法。建議盡可能編寫單元測試,并針對無法單元測試的行為退回到集成測試,但使用此類高性能方式在 ASP.NET Core 中運行集成測試是非常棒的。
?
通過在一個工程里同時模擬了服務(wù)端(TestServer)和客戶端(HttpClient)的通信,從而達到了整體測試WebApi接口的目的,相關(guān)的代碼放在https://github.com/ardalis/GettingStartedWithFilters/tree/master/IntegrationTests?。文章對ASP.NET CORE MVC的篩選器進行測試,由于很難通過編寫單元測試來測試此類場景,但是可以通過ASP.NET Core 的集成測試來達到相同的目的。
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Filters101;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.TestHost;
?
namespace IntegrationTests
{
??? public class AuthorsControllerTestBase
??? {
??????? protected HttpClient GetClient()
??????? {
??????????? var builder = new WebHostBuilder()
??????????????? .UseContentRoot(Directory.GetCurrentDirectory())
??????????????? .UseStartup<Startup>()
??????????????? .UseEnvironment("Testing");
??????????? var server = new TestServer(builder);
??????????? var client = server.CreateClient();
??????????? // client always expects json results
??????????? client.DefaultRequestHeaders.Clear();
??????????? client.DefaultRequestHeaders.Accept.Add(
??????????????? new MediaTypeWithQualityHeaderValue("application/json"));
??????????? return client;
??????? }
??? }
}
?
?
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Filters101.Models;
using Newtonsoft.Json;
using Xunit;
namespace IntegrationTests.AuthorsController
{
??? public class Get : AuthorsControllerTestBase
??? {
??????? private readonly HttpClient _client;
??????? public Get()
??????? {
??????????? _client = base.GetClient();
??????? }
??????? [Theory]
??????? [InlineData("authors")]
??????? [InlineData("authors2")]
??????? public async Task ReturnsListOfAuthors(string controllerName)
??????? {
??????????? var response = await _client.GetAsync($"/api/{controllerName}");
??????????? response.EnsureSuccessStatusCode();
??????????? var stringResponse = await response.Content.ReadAsStringAsync();
??????????? var result = JsonConvert.DeserializeObject<IEnumerable<Author>>(stringResponse).ToList();
??????????? Assert.Equal(2, result.Count());
??????????? Assert.Equal(1, result.Count(a => a.FullName == "Steve Smith"));
??????????? Assert.Equal(1, result.Count(a => a.FullName == "Neil Gaiman"));
??????? }
??? }
}
此案例中的客戶端是標(biāo)準的 System.Net.Http.HttpClient,你可以使用它向服務(wù)器發(fā)出請求,正如同通過網(wǎng)絡(luò)一樣。但因為所有請求都在內(nèi)存中進行,所以測試極其快速可靠。在cmd窗口執(zhí)行單元測試,查看測試結(jié)果
相關(guān)文章:
.NET Core系列 : 1、.NET Core 環(huán)境搭建和命令行CLI入門
.NET Core系列 : 2 、project.json 這葫蘆里賣的什么藥
.NET Core系列 :3 、使用多個項目
原文地址:http://www.cnblogs.com/shanyou/p/5770840.html
.NET社區(qū)新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關(guān)注
贊賞
人贊賞
總結(jié)
以上是生活随笔為你收集整理的.NET Core系列 :4 测试的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Jexus支持HTTPS协议
- 下一篇: 有关技术分享