XUNIT是一个测试框架,可以针对.net/core测试。一般是针对类的Public方法进行测试,也就是对行为进行测试,如果是私有方法需要改变修饰符才能测试。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2tuTM5sP-1679620493695)(C:\Users\29310\AppData\Roaming\Typora\typora-user-images\image-20230322135913491.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CmwyLtzH-1679620493696)(C:\Users\29310\AppData\Roaming\Typora\typora-user-images\image-20230322140456987.png)]
.Net Framework
.Net Core
.Net Standard:.NET Standard是一套协议规范,不像.NET Framework,后者是一个完整的技术框架,而前者只是定义了一套规范,遵守这套规范的.NET Standard类库可以被不同.NET框架引用,比如.NET Core项目和.NET Framework项目都可以引用这个类库。
UWP:在Windows 10 Mobile/Surface(Windows平板电脑)/PC/Xbox/HoloLens等平台上运行,uwp不同于传统pc上的exe应用,也跟只适用于手机端的app有本质区别。它并不是为某一个终端而设计,而是可以在所有windows10设备上运行
Xamarin: 是一个开放源代码平台,用于通过 .NET 构建适用于 iOS、Android 和 Windows 的新式高性能应用程序。 Xamarin 是一个抽象层,可管理共享代码与基础平台代码的通信。 Xamarin 在提供便利(如内存分配和垃圾回收)的托管环境中运行。
Arrange: 在这里做一些先决的设定。例如创建对象实例,数据,输入等。
Act: 在这里执行生产代码并返回结果。例如调用方法或者设置属性。
Assert:在这里检查结果,会产生测试通过或者失败两种结果。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdyhJtaR-1679620493697)(C:\Users\29310\AppData\Roaming\Typora\typora-user-images\image-20230322142648593.png)]
[Fact]//表示当前是测试方法 标记的测试方法不能有方法参数
public void ShouldAdd()
{
// Arrange
var sut = new Demo.calculate();//sut - System Under Test
// Act
var result = sut.Add(2,3);
// Assert
Assert.Equal(5,result);//前面第一个参数是我们想要的结果,第二个是测试的结果
}
第一种是直接在里面用vs运行。
第二种cmd:找到当前的xunit文件位置 dotnet test执行所有测试,dotnet test --help帮助
Assert基于代码的返回值、对象的最终状态、事件是否发生等情况来评估测试的结果
Assert的结果可能是Pass或者Fail
如果所有的asserts都通过了,那么整个测试就通过了。
如果任何assert 失败了,那么结果就失败了。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kDdXZAv0-1679620493697)(C:\Users\29310\AppData\Roaming\Typora\typora-user-images\image-20230322144717063.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RTWRYTBi-1679620493697)(C:\Users\29310\AppData\Roaming\Typora\typora-user-images\image-20230322144824151.png)]
using System;
using System.Collections.Generic;
using System.Text;
using Xunit;
namespace DemoTest
{
public class PatientShould
{
/// <summary>
/// bool类型
/// </summary>
[Fact]
public void Benewisture()
{
// Arrange
var sut = new Demo.Patient();
// Act
var result = sut.IsNew;
// Assert
Assert.True(result);
}
/// <summary>
/// string类型
/// </summary>
[Fact]
public void FullNameTest()
{
var sut = new Demo.Patient()
{
FirstName = "懒",
LastName="洋洋"
};
var result = sut.FullName;
Assert.Equal("懒洋洋",result);
Assert.StartsWith("懒",result);
Assert.EndsWith("洋洋",result);
Assert.Contains("洋",result);
}
/// <summary>
/// 数据类型
/// </summary>
[Fact]
public void bloodSugarValueTest()
{
var sut = new Demo.Patient();
var result = sut.bloodSugar;
Assert.Equal(4.9f,result);
Assert.InRange(result,3.6f,6.1f);//区间值
}
/// <summary>
/// class类型
/// </summary>
[Fact]
public void PatientIsNull()
{
var sut = new Demo.Patient();
Assert.Null(sut.FirstName);
//Assert.NotNull(sut.FirstName);
}
/// <summary>
/// list类型
/// </summary>
[Fact]
public void HistroyAddOrSelect()
{
var sut = new Demo.Patient();
sut.Histroy.Add("社牛");
sut.Histroy.Add("社恐");
sut.Histroy.Add("挖野菜");
sut.Histroy.Add("恋爱脑");
List<string> Health = new List<string>()
{
"社牛",
"社恐",
"挖野菜",
"恋爱脑"
};
Assert.Contains("挖野菜", sut.Histroy);
Assert.DoesNotContain("IKUN",sut.Histroy);
//Assert.Contains(sut.Histroy,u=>u.StartsWith("牛"));
Assert.Contains(sut.Histroy,u=>u.Length>=2);
Assert.Equal(Health,sut.Histroy);
}
/// <summary>
/// 判断是否是一个实列
/// </summary>
[Fact]
public void BeAPerson()
{
var p = new Demo.Patient();
var pr = new Demo.Person();
Assert.IsType<Demo.Patient>(p);
Assert.IsNotType<Demo.Person>(p);
Assert.IsAssignableFrom<Demo.Person>(p);
Assert.NotSame(p,pr);
//Assert.Same(p, pr);//是不是一个实列
}
/// <summary>
/// 异常
/// </summary>
[Fact]
public void ExpretionError()
{
var ex = Assert.Throws<InvalidOperationException>(()=>new Demo.Patient().NotMessage());
Assert.Equal("不能执行这个东西",ex.Message);
}
/// <summary>
/// 事件是否执行
/// </summary>
[Fact]
public void functionExecution()
{
var p = new Demo.Patient();
Assert.Raises<EventArgs>(
handler => p.PatienSlept += handler,
handler => p.PatienSlept -= handler,
() => p.Sleep());
}
/// <summary>
/// 事件是否改变
/// </summary>
[Fact]
public void functionUpdate()
{
var p = new Demo.Patient();
Assert.PropertyChanged(p, nameof(p.HeartBeatRate), () => p.IncreaseHeartBeatRate());
}
}
}
using Hangfire.Annotations;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text;
namespace Demo
{
public class Patient: Person, INotifyPropertyChanged
{
public Patient()
{
IsNew = true;
bloodSugar = 4.9f;//这里记录下这个加f是什么意思是为了防止丢失精度
Histroy = new List<string>();
}
public string FullName => $"{FirstName}{LastName}";
public int HeartBeatRate { get; set; }
public bool IsNew { get; set; }
public float bloodSugar { get; set; }
public List<string> Histroy { get; set; }
public event EventHandler<EventArgs> PatienSlept;//event 事件 事件委托类型
public event PropertyChangedEventHandler PropertCyhanged;
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void Onchangenoti([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public void OnPatienSlept()
{
PatienSlept?.Invoke(this,EventArgs.Empty);//为委托事件没有数据的提供数据
}
public void Sleep()
{
OnPatienSlept();
}
public void IncreaseHeartBeatRate()
{
HeartBeatRate = CalculateHeartBeatRate() + 2;
Onchangenoti(nameof(HeartBeatRate));
}
private int CalculateHeartBeatRate()
{
var random = new Random();
return random.Next(1,100);
}
public void NotMessage()
{
throw new InvalidOperationException("不能执行这个东西");
}
}
}
在分组中选择特征,可以将他作用到类上面和方法上面
cmd指令:dotnet test --filter Category=New 单个 dotnet test --filter “Category=New|Category=Name”
[Fact(Skip =“不需要跑这个测试”)]
cmd指令:dotnet test --filter Category=New --logger:trx
写提示
private readonly ITestOutputHelper _outHelp;
_task =fixture.Task;
IDisposable实现接口
public void Dispose()
{
_outHelp.WriteLine("清理资源");
}
[Collection("Long Time Task Collection")]
[InlineData()]
//第一种数据来源
[Theory]
[InlineData(1,2,3)]
[InlineData(4,2,6)]
[InlineData(5,2,7)]
[InlineData(6,2,8)]
public void ShouldAdd(int x,int y,int expression)
{
var sut = new Demo.calculate();
var result = sut.Add(x, y);
Assert.Equal(expression, result);
}
[MemberData(nameof(calculateDate.TestDate),MemberType =typeof(calculateDate))]
//第二种数据来源
[Theory]
[MemberData(nameof(calculateDate.TestDate),MemberType =typeof(calculateDate))]
public void ShouldAdd2(int x, int y, int expression)
{
var sut = new Demo.calculate();
var result = sut.Add(x, y);
Assert.Equal(expression, result);
}
先声明一个csv文件写入数据(将属性改为复制)
然后写一个类接受数据
/// <summary>
/// 读取文件并返回数据集合
/// </summary>
public class CalculatorCsvData
{
public static IEnumerable<object[]> TestData
{
get
{
//把csv文件中的数据读出来,转换
string[] csvLines = File.ReadAllLines("TestData.csv");
var testCases = new List<object[]>();
foreach (var csvLine in csvLines)
{
IEnumerable<int> values = csvLine.Trim().Split(',').Select(int.Parse);
object[] testCase = values.Cast<object>().ToArray();
testCases.Add(testCase);
}
return testCases;
}
}
}
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using Xunit.Sdk;
namespace DemoTest
{
public class CalculatorDataAttribute : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] { 0, 100, 100 };//yield 提供下一个元素
yield return new object[] { 1, 99, 100 };
yield return new object[] { 2, 98, 100 };
yield return new object[] { 3, 97, 100 };
}
}
}
est
{
public class CalculatorDataAttribute : DataAttribute
{
public override IEnumerable<object[]> GetData(MethodInfo testMethod)
{
yield return new object[] { 0, 100, 100 };//yield 提供下一个元素
yield return new object[] { 1, 99, 100 };
yield return new object[] { 2, 98, 100 };
yield return new object[] { 3, 97, 100 };
}
}
}