|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
using Xunit;
|
|
|
using Xunit.Abstractions;
|
|
|
using Xunit.Extensions;
|
|
|
using Xunit.Sdk;
|
|
|
|
|
|
using xUnitStudy.Model;
|
|
|
|
|
|
namespace xUnitStudy.WebApi.Test
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// 测试类级别的共享(类内所有测试用例,共享一个类的实例)
|
|
|
/// </summary>
|
|
|
public class UseIClassFixtureTest:IClassFixture<ClassFixtureDemo>, IDisposable
|
|
|
{
|
|
|
/* IClassFixture使用步骤:
|
|
|
*
|
|
|
* 01:创建自定义的Fixture类,添加构造函数;如需做清理,则实现IDisposable接口
|
|
|
* 02:创建具体的测试类,并继承 IClassFixture<T>(T 即是 自定义的Fixture类)
|
|
|
* 03:在测试类的构造函数中添加对应的注入参数来获取Fixture,这样的设计使得我们在测试类中所有的测试用例中共享一些Context数据.
|
|
|
* xUnit.Net 会自动发现和运用
|
|
|
*
|
|
|
* 执行流程:
|
|
|
*
|
|
|
* 发现测试类
|
|
|
*
|
|
|
* xUnit 发现测试类相关共享Fixture,创建共享实例并保存,与测试类关联
|
|
|
*
|
|
|
* 用例b:创建测试类实例 --> 获取共享Fixture --> 构造函数 --> 用例1 --> Dispose()方法 --> 结束测试类实例 --> 完成
|
|
|
*
|
|
|
* 用例a:创建测试类实例 --> 获取共享Fixture --> 构造函数 --> 用例2 --> Dispose()方法 --> 结束测试类实例 --> 完成
|
|
|
*
|
|
|
* 用例x:创建测试类实例 --> 获取共享Fixture --> 构造函数 --> 用例2 --> Dispose()方法 --> 结束测试类实例 --> 完成
|
|
|
*
|
|
|
* 用例m:创建测试类实例 --> 获取共享Fixture--> 构造函数 --> 用例2 --> Dispose()方法 --> 结束测试类实例 --> 完成
|
|
|
|
|
|
* ........
|
|
|
|
|
|
* 本测试类中所有用例完成
|
|
|
|
|
|
* 清理共享实例
|
|
|
*
|
|
|
*
|
|
|
* 特别注意:
|
|
|
* 由于测试用例执行顺序不固定,还可能并行运行
|
|
|
* 所以对共享的使用,应避免出现竞态条件。
|
|
|
* 否则,很容易因共享类的竞态条件,导致单元测试失败。
|
|
|
* 因此:共享资源,只适合读,不适合写,使用须谨慎。
|
|
|
*/
|
|
|
ClassFixtureDemo fixtureDemo;
|
|
|
|
|
|
public UseIClassFixtureTest(ClassFixtureDemo fixture)
|
|
|
{
|
|
|
this.fixtureDemo = fixture;
|
|
|
}
|
|
|
|
|
|
|
|
|
[Fact]
|
|
|
public void NotNull_Test()
|
|
|
{
|
|
|
Assert.NotNull(fixtureDemo);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
public void GetPersons_Test()
|
|
|
{
|
|
|
var persons = fixtureDemo.Persons;
|
|
|
//因为共享,所以数量不一定是初始值3
|
|
|
//Assert.Equal(3,fixtureDemo.Persons.Count);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
public void AddPerson_Test()
|
|
|
{
|
|
|
var callTimes_start = fixtureDemo.CallTimes;
|
|
|
|
|
|
var person1 = new Person() { Id=1,FirstName="first",LastName="last"};
|
|
|
var person2 = new Person() {Id=200};
|
|
|
|
|
|
//因为共享,在不能保证单元测试的执行先后顺充时,或者并行执行单元测试时,可能id=1的项已被删除,也可能没被删除
|
|
|
//所以,result1可能失败,也可能成功
|
|
|
|
|
|
var result1 = fixtureDemo.AddPerson(person1);
|
|
|
var result2 = fixtureDemo.AddPerson(person2);
|
|
|
|
|
|
//Assert.False(result1.result); 执行成功与否,取决于添加和删除单元测试的执行顺序。因为执行顺序不能确定,所以结果不定。
|
|
|
Assert.True(result2.result);
|
|
|
|
|
|
Assert.Equal(4, fixtureDemo.Persons.Count);
|
|
|
Assert.Contains(person2, fixtureDemo.Persons);
|
|
|
|
|
|
var callTimes_end = fixtureDemo.CallTimes;
|
|
|
Assert.Equal(2, callTimes_end - callTimes_start);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
public void RemovePerson_Test()
|
|
|
{
|
|
|
var person1 = new Person() { Id = 1, FirstName = "first", LastName = "last" };
|
|
|
var person2 = new Person() { Id = 100 };
|
|
|
var result1 = fixtureDemo.RemovePerson(person1);
|
|
|
var result2 = fixtureDemo.RemovePerson(person2);
|
|
|
|
|
|
Assert.True(result1.result);
|
|
|
Assert.False(result2.result);
|
|
|
|
|
|
Assert.DoesNotContain(person1, fixtureDemo.Persons);
|
|
|
Assert.DoesNotContain(person2, fixtureDemo.Persons);
|
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
|
{
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|