日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

使用xUnit为.net core程序进行单元测试(中)

發(fā)布時間:2023/12/4 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 使用xUnit为.net core程序进行单元测试(中) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

第一部分:??使用xUnit為.net core程序進行單元測試(上), 下面有一點點內容是重疊的....

String Assert

測試string是否相等

[Fact]

? ? ? ? public void CalculateFullName()

? ? ? ? {

? ? ? ? ? ? var p = new Patient

? ? ? ? ? ? {

? ? ? ? ? ? ? ? FirstName = "Nick",

? ? ? ? ? ? ? ? LastName = "Carter"

? ? ? ? ? ? };

? ? ? ? ? ? Assert.Equal("Nick Carter", p.FullName);

? ? ? ? }

然后你需要Build一下,這樣VS Test Explorer才能發(fā)現(xiàn)新的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是區(qū)分大小寫的,這樣就會失敗:

可以為這些方法添加一個參數(shù)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,測試通過。

數(shù)值 Assert

首先為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。

浮點型數(shù)值的Assert

在被測項目添加這兩個類:

namespace Hospital

{

? ? public abstract class Worker

? ? {

? ? ? ? public string Name { get; set; }


? ? ? ? public abstract double TotalReward { get; }

? ? ? ? public abstract double Hours { get; }

? ? ? ? public double Salary => TotalReward / Hours;

? ? }


? ? public class Plumber : Worker

? ? {

? ? ? ? public override double TotalReward => 200;

? ? ? ? public override double Hours => 3;

? ? }

}

然后針對Plumber建立一個測試類 PlumberShould.cs, 并建立第一個test:

namespace Hospital.Tests

{

? ? public class PlumberShould

? ? {

? ? ? ? [Fact]

? ? ? ? public void HaveCorrectSalary()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Equal(66.666, plumber.Salary);

? ? ? ? }

? ? }

}

Build項目, 然后再Test Explorer里面選擇按Class分類顯示Tests:

Run Selected Test, 結果會失敗:

這是一個精度的問題.

在Assert.Equal方法, 可以添加一個precision參數(shù), 設置精度為3:

[Fact]

? ? ? ? public void HaveCorrectSalary()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Equal(66.666, plumber.Salary, precision: 3);

? ? ? ? }

Build, Run Test:

因為有四舍五入的問題, 所以test仍然fail了.

所以還需要改一下:

[Fact]

? ? ? ? public void HaveCorrectSalary()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Equal(66.667, plumber.Salary, precision: 3);

? ? ? ? }

這次會pass的:

Assert Null值

[Fact]

? ? ? ? public void NotHaveNameByDefault()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Null(plumber.Name);

? ? ? ? }


? ? ? ? [Fact]

? ? ? ? public void HaveNameValue()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber

? ? ? ? ? ? {

? ? ? ? ? ? ? ? Name = "Brian"

? ? ? ? ? ? };

? ? ? ? ? ? Assert.NotNull(plumber.Name);

? ? ? ? }

有兩個方法, Assert.Null 和 Assert.NotNull, 直接傳入期待即可.

測試會Pass的.

集合 Collection Assert

修改一下被測試類, 添加一個集合屬性, 并賦值:

namespace Hospital

{

? ? public abstract class Worker

? ? {

? ? ? ? public string Name { get; set; }


? ? ? ? public abstract double TotalReward { get; }

? ? ? ? public abstract double Hours { get; }

? ? ? ? public double Salary => TotalReward / Hours;


? ? ? ? public List<string> Tools { get; set; }

? ? }


? ? public class Plumber : Worker

? ? {

? ? ? ? public Plumber()

? ? ? ? {

? ? ? ? ? ? Tools = new List<string>()

? ? ? ? ? ? {

? ? ? ? ? ? ? ? "螺絲刀",

? ? ? ? ? ? ? ? "扳子",

? ? ? ? ? ? ? ? "鉗子"

? ? ? ? ? ? };

? ? ? ? }


? ? ? ? public override double TotalReward => 200;

? ? ? ? public override double Hours => 3;

? ? }

}

測試是否包含某個元素, Assert.Contains():

[Fact]

? ? ? ? public void HaveScrewdriver()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Contains("螺絲刀", plumber.Tools);

? ? ? ? }

Build, Run Test, 結果Pass.

修改一下名字, 讓其Fail:

這個失敗信息還是很詳細的.

相應的還有一個Assert.DoesNotContain()方法, 測試集合是否不包含某個元素.

[Fact]

? ? ? ? public void NotHaveKeyboard()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.DoesNotContain("鍵盤", plumber.Tools);

? ? ? ? }


這個test也會pass.

Predicate:

測試一下集合中是否包含符合某個條件的元素:

[Fact]

? ? ? ? public void HaveAtLeastOneScrewdriver()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.Contains(plumber.Tools, t => t.Contains("螺絲刀"));

? ? ? ? }

使用的是Assert.Contains的一個overload方法, 它的第一個參數(shù)是集合, 第二個參數(shù)是Predicate.

Build, Run Test, 會Pass的.

比較集合相等:

添加Test:

[Fact]

? ? ? ? public void HaveAllTools()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? var expectedTools = new []

? ? ? ? ? ? {

? ? ? ? ? ? ? ? "螺絲刀",

? ? ? ? ? ? ? ? "扳子",

? ? ? ? ? ? ? ? "鉗子"

? ? ? ? ? ? };

? ? ? ? ? ? Assert.Equal(expectedTools, plumber.Tools);

? ? ? ? }

注意, Plumber的tools類型是List, 這里的expectedTools類型是array.

這個test 仍然會Pass.

如果修改一個元素, 那么測試會Fail, 信息如下:

Assert針對集合的每個元素:

如果想對集合的每個元素進行Assert, 當然可以通過循環(huán)來Assert了, 但是更好的寫法是調用Assert.All()方法:

[Fact]

? ? ? ? public void HaveNoEmptyDefaultTools()

? ? ? ? {

? ? ? ? ? ? var plumber = new Plumber();

? ? ? ? ? ? Assert.All(plumber.Tools, t => Assert.False(string.IsNullOrEmpty(t)));

? ? ? ? }

這個測試會Pass.

如果在被測試類的Tools屬性添加一個空字符串, 那么失敗信息會是:

這里寫到, 4個元素里面有1個沒有pass.

針對Object類型的Assert

?首先再添加一個Programmer類:

public class Programmer : Worker{ ? ? ? ?public override double TotalReward => 1000; ? ? ? ?public override double Hours => 3.5;}

然后建立一個WorkerFactory:

namespace Hospital

{

? ? public class WorkerFactory

? ? {

? ? ? ? public Worker Create(string name, bool isProgrammer = false)

? ? ? ? {

? ? ? ? ? ? if (isProgrammer)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? return new Programmer { Name = name };

? ? ? ? ? ? }

? ? ? ? ? ? return new Plumber { Name = name };

? ? ? ? }

? ? }

}

判斷是否是某個類型 Assert.IsType<Type>(xx):
建立一個測試類 WorkerShould.cs和一個test:

namespace Hospital.Tests

{

? ? public class WorkerShould

? ? {

? ? ? ? [Fact]

? ? ? ? public void CreatePlumberByDefault()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? Worker worker = factory.Create("Nick");

? ? ? ? ? ? Assert.IsType<Plumber>(worker);

? ? ? ? }

? ? }

}

Build, Run Test: 結果Pass.

相應的, 還有一個Assert.IsNotType<Type>(xx)方法.

利用Assert.IsType<Type>(xx)的返回值, 它會返回Type(xx的)的這個實例, 添加個一test:

[Fact]

? ? ? ? public void CreateProgrammerAndCastReturnedType()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? Worker worker = factory.Create("Nick", isProgrammer: true);

? ? ? ? ? ? Programmer programmer = Assert.IsType<Programmer>(worker);

? ? ? ? ? ? Assert.Equal("Nick", programmer.Name);

? ? ? ? }


uild, Run Tests: 結果Pass.

Assert針對父類:

寫這樣一個test, 創(chuàng)建的是一個promgrammer, Assert的類型是它的父類Worker:

[Fact]

? ? ? ? public void CreateProgrammer_AssertAssignableTypes()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? Worker worker = factory.Create("Nick", isProgrammer: true);

? ? ? ? ? ? Assert.IsType<Worker>(worker);

? ? ? ? }

這個會Fail:

這時就應該使用這個方法,?Assert.IsAssignableFrom<祖先類>(xx):

[Fact]

? ? ? ? public void CreateProgrammer_AssertAssignableTypes()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? Worker worker = factory.Create("Nick", isProgrammer: true);

? ? ? ? ? ? Assert.IsAssignableFrom<Worker>(worker);

? ? ? ? }

Build, Run Tests: Pass.

Assert針對對象的實例

判斷兩個引用是否指向不同的實例?Assert.NotSame(a, b):

[Fact]

? ? ? ? public void CreateSeperateInstances()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? var p1 = factory.Create("Nick");

? ? ? ? ? ? var p2 = factory.Create("Nick");

? ? ? ? ? ? Assert.NotSame(p1, p2);

? ? ? ? }

由工廠創(chuàng)建的兩個對象是不同的實例, 所以這個test會Pass.

相應的還有個Assert.Same(a, b)?方法.

Assert 異常

為WorkFactory先添加一個異常處理:

namespace Hospital

{

? ? public class WorkerFactory

? ? {

? ? ? ? public Worker Create(string name, bool isProgrammer = false)

? ? ? ? {

? ? ? ? ? ? if (name == null)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? throw new ArgumentNullException(nameof(name));

? ? ? ? ? ? }

? ? ? ? ? ? if (isProgrammer)

? ? ? ? ? ? {

? ? ? ? ? ? ? ? return new Programmer { Name = name };

? ? ? ? ? ? }

? ? ? ? ? ? return new Plumber { Name = name };

? ? ? ? }

? ? }

}

如果在test執(zhí)行代碼時拋出異常的話, 那么test會直接fail掉.

所以應該使用Assert.Throws<ArgumentNullException>(...)方法來Assert是否拋出了特定類型的異常.

添加一個test:

[Fact]

? ? ? ? public void NotAllowNullName()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? // var p = factory.Create(null); // 這個會失敗

? ? ? ? ? ? Assert.Throws<ArgumentNullException>(() => factory.Create(null));

? ? ? ? }

注意不要直接運行會拋出異常的代碼. 應該在Assert.Throws<ET>()的方法里添加lambda表達式來調用方法.

這樣的話就會pass.

如果被測試代碼沒有拋出異常的話, 那么test會fail的. 把拋異常代碼注釋掉之后再Run:

更具體的, 還可以指定參數(shù)的名稱:

[Fact]

? ? ? ? public void NotAllowNullName()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? // Assert.Throws<ArgumentNullException>(() => factory.Create(null));

? ? ? ? ? ? Assert.Throws<ArgumentNullException>("name", () => factory.Create(null));

? ? ? ? }

這里就是說異常里應該有一個叫name的參數(shù).

Run: Pass.

如果把"name"改成"isProgrammer", 那么這個test會fail:

利用Assert.Throws<ET>()的返回結果, 其返回結果就是這個拋出的異常實例.

[Fact]

? ? ? ? public void NotAllowNullNameAndUseReturnedException()

? ? ? ? {

? ? ? ? ? ? var factory = new WorkerFactory();

? ? ? ? ? ? ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => factory.Create(null));

? ? ? ? ? ? Assert.Equal("name", ex.ParamName);

? ? ? ? }

Assert Events 是否發(fā)生(Raised)

回到之前的Patient類, 添加如下代碼:

public void Sleep()

? ? ? ? {

? ? ? ? ? ? OnPatientSlept();

? ? ? ? }


? ? ? ? public event EventHandler<EventArgs> PatientSlept;


? ? ? ? protected virtual void OnPatientSlept()

? ? ? ? {

? ? ? ? ? ? PatientSlept?.Invoke(this, EventArgs.Empty);

? ? ? ? }

然后回到PatientShould.cs添加test:

[Fact]

? ? ? ? public void RaiseSleptEvent()

? ? ? ? {

? ? ? ? ? ? var p = new Patient();

? ? ? ? ? ? Assert.Raises<EventArgs>(

? ? ? ? ? ? ? ? handler => p.PatientSlept += handler,?

? ? ? ? ? ? ? ? handler => p.PatientSlept -= handler,?

? ? ? ? ? ? ? ? () => p.Sleep());

? ? ? ? }

Assert.Raises<T>()第一個參數(shù)是附加handler的Action, 第二個參數(shù)是分離handler的Action, 第三個Action是觸發(fā)event的代碼.

Build, Run Test: Pass.

如果注釋掉Patient類里Sleep()方法內部那行代碼, 那么test會fail:

針對INotifyPropertyChanged的特殊Assert:

修改Patient代碼:


namespace Hospital

{

? ? public class Patient: INotifyPropertyChanged

? ? {

? ? ? ? public Patient()

? ? ? ? {

? ? ? ? ? ? IsNew = true;

? ? ? ? ? ? _bloodSugar = 5.0f;

? ? ? ? }


? ? ? ? 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; }


? ? ? ? private float _bloodSugar;

? ? ? ? public float BloodSugar

? ? ? ? {

? ? ? ? ? ? get => _bloodSugar;

? ? ? ? ? ? set => _bloodSugar = value;

? ? ? ? }


? ? ? ? public void HaveDinner()

? ? ? ? {

? ? ? ? ? ? var random = new Random();

? ? ? ? ? ? _bloodSugar += (float)random.Next(1, 1000) / 1000;

? ? ? ? ? ? OnPropertyChanged(nameof(BloodSugar));

? ? ? ? }


? ? ? ? public void IncreaseHeartBeatRate()

? ? ? ? {

? ? ? ? ? ? HeartBeatRate = CalculateHeartBeatRate() + 2;

? ? ? ? }


? ? ? ? private int CalculateHeartBeatRate()

? ? ? ? {

? ? ? ? ? ? var random = new Random();

? ? ? ? ? ? return random.Next(1, 100);

? ? ? ? }


? ? ? ? public void Sleep()

? ? ? ? {

? ? ? ? ? ? OnPatientSlept();

? ? ? ? }


? ? ? ? public event EventHandler<EventArgs> PatientSlept;


? ? ? ? protected virtual void OnPatientSlept()

? ? ? ? {

? ? ? ? ? ? PatientSlept?.Invoke(this, EventArgs.Empty);

? ? ? ? }


? ? ? ? public event PropertyChangedEventHandler PropertyChanged;


? ? ? ? protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)

? ? ? ? {

? ? ? ? ? ? PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

? ? ? ? }

? ? }

}

添加一個Test:

[Fact]

? ? ? ? public void RaisePropertyChangedEvent()

? ? ? ? {

? ? ? ? ? ? var p = new Patient();

? ? ? ? ? ? Assert.PropertyChanged(p, "BloodSugar", () => p.HaveDinner());

? ? ? ? }

針對INotifyPropertyChanged, 可以使用Assert.PropertyChanged(..)?這個專用的方法來斷定PropertyChanged的Event是否被觸發(fā)了.

Build, Run Tests: Pass.

到目前為止, 介紹的都是入門級的內容.

接下來要介紹的是稍微進階一點的內容了.

相關內容:?

  • 使用xUnit為.net core程序進行單元測試(上)

  • 舍棄Nunit擁抱Xunit

  • 使用Xunit來進行單元測試

  • 在XUnit中用Moq怎樣模擬EntityFramework Core下的DbSet

原文地址:https://www.cnblogs.com/cgzl/p/8287588.html


.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com

總結

以上是生活随笔為你收集整理的使用xUnit为.net core程序进行单元测试(中)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。