您好,登錄后才能下訂單哦!
怎樣使用xUnit為.net core程序進行單元測試,相信很多沒有經驗的人對此束手無策,為此本文總結了問題出現的原因和解決方法,通過這篇文章希望你能解決這個問題。
可以頻繁的進行測試
可以在任何時間進行測試,也可以按計劃定時進行,例如:可以在半夜進行自動測試。
肯定比人工測試要快。
可以更快速的發現錯誤。
基本上是非常可靠的。
測試代碼與生產代碼緊密結合。
使得開發團隊更具有幸福感!
縱軸表示測試的深度,也就是說測試的細致程度。
橫軸則表示測試的覆蓋程度。
Unit Test 單元測試, 它可以測試一個類,或者一個類的某個功能,它具有很好的深度,但是對整個應用來說它不具備很好的覆蓋面。
Integration Test 集成測試,它沒有單元測試那么細致,但是具有相對較好的測試覆蓋面。例如它可以測試功能的組合,以及像數據庫或文件系統這樣的外部資源等。
Subcutaneous Test 皮下測試,這種測試作用于UI層的下面一層,這也意味著它對整個應用來說有很好的覆蓋率,但是深度欠佳。那一個MVC結構的應用來說,它就是針對剛好在Controller下面一層的測試,對于Web service來說,它就是對節點下面那層的測試。
UI測試,它的測試覆蓋面很廣,直接從UI層面進行測試,但是深度欠佳。
從速度來看 單元是最快的,而UI測試是最慢的。
從脆弱性來看 UI測試是最差的,程序修改后極有可能需要修改測試代碼,而單元測試是最好的。
public void IncreaseHeartBeatRate()
{
HeartBeatRate = CalculateHeartBeatRate() + 2;
}
private int CalculateHeartBeatRate()
{
var random = new Random();
return random.Next(1, 100);
}
大多數情況下單元測試都應該是針對類的行為進行測試的,也就是public方法。當然也純在不同的觀點。
如果想要對private方法進行測試的話,是有很多缺點的:
首先需要修改方法的訪問限制需要從private改為public,這就破壞了面向對象的封裝性。
再者,這其實測試的是類的具體實現細節,而不是類的行為。如果我們想要對類的內部進行重構的話,就會破壞測試,導致測試也必須重構。如果必須對private方法進行測試,那么首先建議您把private修飾符改成internal,然后修改該項目(project)的AssemblyInfo.cs,它在項目的Debug或者Release文件夾下。代碼如下:
[assembly: InternalsVisibleTo("Hospital.Tests")]
這表示Hospital.Tests這個測試項目可以訪問該項目生產代碼(production code)的internal方法。
Arrange,這里做一些先決的設定。例如創建對象實例,數據,輸入等等。
Act,在這里執行生產代碼并返回結果。例如調用方法,或者設置屬性(Properties)。
Assert,在這里檢查結果。測試通過或者失敗。
官網:https://xunit.github.io/
xUnit是一個測試框架,可以針對.net/core進行測試。
測試項目需引用被項目從而對其進行測試,測試項目同時需要引用xUnit庫。測試編寫好后,用Test Runner來運行測試。Test Runner可以讀取測試代碼,并且會知道我們所使用的測試框架,然后執行,并顯示結果。目前可用的Test Runner包括vs自帶的Test Explorer,或者dotnet core命令行,以及第三方工具,例如resharper等等。
.net full, .net core, .net standard, uwp, xamarin.
[Fact]
public void TestIncreaseHeartBeatRate()
{
var patient = new Patient(); // Arrange
patient.IncreaseHeartBeatRate(); // Act
Assert.InRange(patient.HeartBeatRate, 40, 100); // Assert
}
首先建立一個C# library項目,叫Hospital(下面部分截圖有個拼寫錯誤,應該是Hospital),然后建立一個xUnit Test項目,叫Hospital.Tests:
可以看到Hospital.Tests已經包含里這幾個庫:
然后為Hospital.Tests添加到Hospital項目的引用。
首先把剛才建立的Hospital.Tests項目移除(目錄需要手動刪除).
然后打開項目位置:
按住shift打開命令行:
用命令行創建項目:
創建 Hospital.Tests目錄,進入目錄,使用命令dotnet new xunit
創建xUnit單元測試項目。
添加項目的引用:
最后添加項目到解決方案:
回到VS界面,提示重新加載:
確認后,VS中解決方案結構如:
對測試項目的文件名進行一些重構,編寫以下代碼,并進行Build:
從Test Explorer我們可以看到一個待測試的項目。
在這里,我們可以對測試項目進行分組和排序,如圖:
想要運行所有的測試,就點擊上面的Run All按鈕。如果像運行單個測試,那么右擊選擇Run Selected Tests:
運行后,可以看到結果,Passed:
我們同樣可以通過命令行來進行測試:
進入到Tests目錄,執行 dotnet test
命令,所有的測試都會被發現,然后被執行:
因為我們并沒有在測試方法中寫任何的Assert,所以測試肯定是通過的,但這個測試也是個無效的測試。
Assert做什么?Assert基于代碼的返回值、對象的最終狀態、事件是否發生等情況來評估測試的結果。Assert的結果可能是Pass或者Fail。如果所有的asserts都pass了,那么整個測試就pass了;如果有任何assert fail了,那么測試就fail了。
xUnit提供了以下類型的Assert:
boolean:True/False
String:相等/不等,是否為空,以..開始/結束,是否包含子字符串,匹配正則表達式
數值型:相等/不等,是否在某個范圍內,浮點的精度
Collection:內容是否相等,是否包含某個元素,是否包含滿足某種條件(predicate)的元素,是否所有的元素都滿足某個assert
Raised events:Custom events,Framework events(例如:PropertyChanged)
Object Type:是否是某種類型,是否某種類型或繼承與某種類型
一種建議的做法是,每個test方法里面只有一個assert。
而還有一種建議就是,每個test里面可以有多個asserts,只要這些asserts都是針對同一個行為就行。
目標類:
public class Patient
{
public Patient()
{
IsNew = true;
}
public string FirstName { get; set; }
public string LastName { get; set; }
public string FullName => $"{FirstName} {LastName}";
public int HeartBeatRate { get; set; }
public bool IsNew { get; set; }
public void IncreaseHeartBeatRate()
{
HeartBeatRate = CalculateHeartBeatRate() + 2;
}
private int CalculateHeartBeatRate()
{
var random = new Random();
return random.Next(1, 100);
}
}
測試類:
public class PatientShould
{
[Fact]
public void HaveHeartBeatWhenNew()
{
var patient = new Patient();
Assert.True(patient.IsNew);
}
}
運行測試:
結果符合預期,測試通過。
改為Assert.False()的話:
測試Fail。
測試string是否相等:
[Fact]
public void CalculateFullName()
{
var p = new Patient
{
FirstName = "Nick",
LastName = "Carter"
};
Assert.Equal("Nick Carter", p.FullName);
}
然后你需要Build一下,這樣VS Test Explorer才能發現新的test。
運行測試,結果Pass:
同樣改一下Patient類(別忘了Build一下),讓結果失敗:
從失敗信息可以看到期待值和實際值。
StartsWith, EndsWith
[Fact]
public void CalculateFullNameStartsWithFirstName()
{
var p = new Patient
{
FirstName = "Nick",
LastName = "Carter"
};
Assert.StartsWith("Nick", p.FullName);
}
[Fact]
public void CalculateFullNameEndsWithFirstName()
{
var p = new Patient
{
FirstName = "Nick",
LastName = "Carter"
};
Assert.EndsWith("Carter", p.FullName);e);
}
Build,然后Run Test,結果Pass:
忽略大小寫 ignoreCase:
string默認的Assert是區分大小寫的,這樣就會失敗:
可以為這些方法添加一個參數ignoreCase設置為true,就會忽略大小寫:
包含子字符串 Contains
[Fact]
public void CalculateFullNameSubstring()
{
var p = new Patient
{
FirstName = "Nick",
LastName = "Carter"
};
Assert.Contains("ck Ca", p.FullName);
}
Build,測試結果Pass。
正則表達式,Matches
測試一下First name和Last name的首字母是不是大寫的:
[Fact]
public void CalculcateFullNameWithTitleCase()
{
var p = new Patient
{
FirstName = "Nick",
LastName = "Carter"
};
Assert.Matches("[A-Z]{1}{a-z}+ [A-Z]{1}[a-z]+", p.FullName);
}
Build,測試通過。
首先為Patient類添加一個property: BloodSugar。
public class Patient
{
public Patient()
{
IsNew = true;
_bloodSugar = 5.0f;
}
private float _bloodSugar;
public float BloodSugar
{
get { return _bloodSugar; }
set { _bloodSugar = value; }
}
...
Equal:
[Fact]
public void BloodSugarStartWithDefaultValue()
{
var p = new Patient();
Assert.Equal(5.0, p.BloodSugar);
}
Build,測試通過。
范圍, InRange:
首先為Patient類添加一個方法,病人吃飯之后血糖升高:
public void HaveDinner()
{
var random = new Random();
_bloodSugar += (float)random.Next(1, 1000) / 100; // 應該是1000}
添加test:
[Fact]
public void BloodSugarIncreaseAfterDinner()
{
var p = new Patient();
p.HaveDinner();
// Assert.InRange<float>(p.BloodSugar, 5, 6);
Assert.InRange(p.BloodSugar, 5, 6);
}
Build,Run Test,結果Fail:
可以看到期待的Range和實際的值,這樣很好。如果你使用Assert.True(xx >= 5 && xx <= 6)
的話,錯誤信息只能顯示True或者False。
因為HaveDinner方法里,表達式的分母應該是1000,修改后,Build,Run,測試Pass。
看完上述內容,你們掌握怎樣使用xUnit為.net core程序進行單元測試的方法了嗎?如果還想學到更多技能或想了解更多相關內容,歡迎關注億速云行業資訊頻道,感謝各位的閱讀!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。