使用xUnit.net 对 .net core 进行单元测试



1.自动化测试综述

1.为什么要进行自动化测试

1.可以在任何时间进行测试。
2.测试速度要比人快。
3.非常可靠。

2.自动化测试的分类

  • 单元测试:测试某个类或者类下的某个方法
  • 集成测试
  • 皮下测试
  • UI 测试

在这里插入图片描述
测试的是 public ,private不太好测试,需要修改代码


2.测试的三个阶段 AAA

  • Arrange:(序列,安排),这里做一些先决的设定,例如创建对象实例,数据,输入等等。
  • Act ,在这里执行生产代码并返回结果,例如调用方法和设置属性。
  • Assert:(主张)在这里检测结果,测试通过或者失败。

xUnit 是一个测试框架,可以针对 .net /core 进行测试。

代码部分:

1.先看目录结构
在这里插入图片描述

  • 命名规则:在类的名字后边加 test 。
  • 命名规则:测试方法的方法名用 ShouldAdd 。
  • 测试的项目,添加 xUnit.net 测试项目。

Cakulator 类

 public class Cakulator
    {
        public int Add(int a, int b)
        {
            return a + b;
        }
    }

CakulatroTest 类

  public class CakulatroTest
    {
        [Fact] //根据这个特性判断出来是个测试方法。

        public void ShouldAdd()
        {
            // Arrange
            var sut = new Cakulator();// system Under Test

            // Act
            var result = sut.Add(1, 2);

            // Assert

            Assert.Equal(3, result);//结果等于3
        }
    }

进行测试:
在这里插入图片描述
在要准备测试的类和方法上直接右键运行。

在这里插入图片描述

3.Assert

  • Assert基于代码的返回值,对象的最终状态,事件是否发生等情况来评估测试结果。
  • Assert的结果可能是 pass 也有可能是 Fail,如果所有的 Assert 都是 Pass ,那么整个测试就 pass 了。如果有任何的 assert fail 了,那么测试就 fail 了。

xUnit 可以进行以下的判断:

在这里插入图片描述
一个test里面应该有多少个 assert

  • 一个 test 方法里,只能有一个 assert 。
  • 一个 test 方法里,可以有多个 Asserts,只要这多个 assert 这对一个 Action 就行。

具体代码:

1.先建一个 Person 类

 public class Person
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

2.再建一个 patient 类


  public   class patient:Person
    {
        public patient()
        {
            IsNew = true; //刚 new 出来的时候,这个 isnew 是 true 。
            BloodSugar = 4.9f;
            History = new List<string>();//把这个要 new 出来.
        }
        public string FullName => $"{LastName}{FirstName}";
        public bool IsNew { get; set; }  //是否是刚出生的。
        public float BloodSugar { get; set; }

        public int  HeartBeatRate { get; set; }
        public void IncressHeartBeatRate()   //计算心跳
        {
            //执行完以后的方法 + 2
            HeartBeatRate = CalulateHeartBeatRate() + 2;
        }

        public List<string> History { get; set; }


        private int CalulateHeartBeatRate()  //心跳
        {
            var random = new Random();
            return random.Next(1,100);
        }
    }

3.使用 xUnit 进行测试:

 public class PatientShould
    {
        // 对 bool 类型进行判断.
        [Fact]
        public void BeNewWhenCreated()
        {
            // arrange

            patient patient = new patient();

            //Act
            bool result = patient.IsNew;

            //Assert

            Assert.True(result);
            // Assert.False(result);
        }

        //对字符串进行判断

        [Fact] //表明这个是个测试方法
        public void HaveCorrctFullName()
        {
            // Arrange (实例化一个你要检查的类)
            patient patient = new patient
            {
                FirstName = "小明",
                LastName = "张"
            };
            // Act 。把需要检查的属性弄出来
            var fullName = patient.FullName;

            //Assert 。进行判断.
            Assert.Equal("张小明", fullName);
            Assert.StartsWith("张", fullName);
            Assert.EndsWith("明", fullName);
            Assert.Contains("小", fullName);
            //是小写但不是大写;
            Assert.NotEqual("李", fullName);
        }


        //对 浮点型 进行判断

        [Fact]
        public void HaveDefaultBloodSugarWhenCreate()
        {
            patient patient = new patient();
            float blooddar = patient.BloodSugar;
            Assert.Equal(4.9f, blooddar, 5);
            //在哪个范围内
            Assert.InRange(blooddar, 3.9f, 6.1f);
        }

        //刚开始创建的时候,名字应该是空;
        [Fact]
        public void HaveNameWhenCreated()
        {
            patient p = new patient();
            var a = p.FirstName;
            Assert.Null(a);
            Assert.NotNull(p);
        }

        //对集合进行测试
        [Fact]
        public void HaveHadColid()
        {
            var p = new patient();
            p.History.Add("感冒");
            p.History.Add("发烧");
            p.History.Add("水痘");
            p.History.Add("腹泻");
            Assert.Contains("感冒", p.History);
            Assert.DoesNotContain("心脏病", p.History);

            //Predicate
            //对集合中的元素判断是否包含
            Assert.Contains(p.History, x => x.StartsWith("水"));
            //对集合内的所有元素都进行判断
            Assert.All(p.History, x => Assert.True(x.Length >= 2));


            // 判断两个集合是否相等

            var diseases = new List<string>
            {
                "感冒",
                "发烧",
                "水痘",
                "腹泻"
            };
            Assert.Equal(p.History, diseases);
        }

        // 对  object 进行测试
        [Fact]
        public void BeAPerson()
        {
            var p1 = new patient();
            var p2 = new patient();
            Assert.IsType<patient>(p1);//p是否是 patient 类型.
            Assert.IsNotType<Person>(p1);//这个就会判断处所。尽管是他的子类.
            Assert.IsAssignableFrom<Person>(p1);//判断是否继承于某个类

            //判断是否是一个实例
            //same 是同一个实例
            Assert.NotSame(p1,p2);
            // Assert.Same(p1,p2);
         }

        // 判断异常
        // 判断抛出的异常是否和我们所期待的相等.
        // 对委托和事件的测试.
        // 写起来有点麻烦,用到再说吧。
    }

在使用 测试资源管理器的时候,如果加断点,要使用 debug 模式,不能进行直接测试

在这里插入图片描述

4.测试的优化

  • 测试分组
  • 忽略测试
  • 自定义测试输出的内容
  • 减少重复代码
  • 共享上下文

注意,在每次测试的时候,都要重新生成一下

1.分组 [ Trait (“Name”,“Value”) ]

  • 方法级
  • Class级

1.代码:

 public class PatientShould
    {
        private readonly ITestOutputHelper output;
        private readonly patient _patient;
        private readonly LongTimeTask _task;

        public PatientShould(ITestOutputHelper output)
        {
            this.output = output;
            _patient=new patient();
            _task=new LongTimeTask();
        }

        // 对 bool 类型进行判断.
        [Fact]
        [Trait("Category","New")]
        public void BeNewWhenCreated()
        {
            output.WriteLine("这是第一个测试");//在这里用 Console.WriteLine()是无效的;
            bool result = _patient.IsNew;
            Assert.True(result);
        }

        [Fact] //表明这个是个测试方法
        [Trait("Category", "Name")]
        public void HaveCorrctFullName()
        {
            patient patient = new patient
            {
                FirstName = "小明",
                LastName = "张"
            };
            var fullName = patient.FullName;
            Assert.Equal("张小明", fullName);
            Assert.StartsWith("张", fullName);
            Assert.EndsWith("明", fullName);
            Assert.Contains("小", fullName);
            //是小写但不是大写;
            Assert.NotEqual("李", fullName);
        }

在测试任务管理器里面,选择分组依据为特征:

在这里插入图片描述

2.输出测试的信息

在测试的时候,console.writeLine( ) 不管用,要使用 outputhelp.WriteLine 进行测试,构造函数引用方法如下。

3.可以跳过去某个测试

[Fact(Skip =“不需要跑这个测试”)]

4.为了防止代码重复,new 的实例,在构造函数里实现

要养成这种习惯:

具体代码如下:

 public class PatientShould
    {
        private readonly ITestOutputHelper output;
        private readonly patient _patient;
        private readonly LongTimeTask _task;

        public PatientShould(ITestOutputHelper output)
        {
            this.output = output;
            // 为减少重复代码,使用构造函数重构
            // 下边都使用同一个构造函数
            _patient=new patient();
            _task=new LongTimeTask();
        }

        // 对 bool 类型进行判断.
        [Fact]
        [Trait("Category","New")]
        public void BeNewWhenCreated()
        {
            output.WriteLine("这是第一个测试");//在这里用 Console.WriteLine()是无效的;
 
            //Act
            bool result = _patient.IsNew;

            //Assert

            Assert.True(result);
            // Assert.False(result);
        }

        //对字符串进行判断

        [Fact] //表明这个是个测试方法
        [Trait("Category", "Name")]
        public void HaveCorrctFullName()
        {
            // Arrange (实例化一个你要检查的类)
            patient patient = new patient
            {
                FirstName = "小明",
                LastName = "张"
            };
            // Act 。把需要检查的属性弄出来
            var fullName = patient.FullName;

            //Assert 。进行判断.
            Assert.Equal("张小明", fullName);
            Assert.StartsWith("张", fullName);
            Assert.EndsWith("明", fullName);
            Assert.Contains("小", fullName);
            //是小写但不是大写;
            Assert.NotEqual("李", fullName);
        }


        //对 浮点型 进行判断

        [Fact]
        [Trait("Category","New")]
        public void HaveDefaultBloodSugarWhenCreate()
        {
            patient patient = new patient();
            float blooddar = patient.BloodSugar;
            Assert.Equal(4.9f, blooddar, 5);
            //在哪个范围内
            Assert.InRange(blooddar, 3.9f, 6.1f);
        }

        //刚开始创建的时候,名字应该是空;
        [Fact(Skip ="不需要跑这个测试")]
        public void HaveNameWhenCreated()
        {
            patient p = new patient();
            var a = p.FirstName;
            Assert.Null(a);
            Assert.NotNull(p);
        }

        //对集合进行测试
        [Fact]
        public void HaveHadColid()
        {
            var p = new patient();
            p.History.Add("感冒");
            p.History.Add("发烧");
            p.History.Add("水痘");
            p.History.Add("腹泻");
            Assert.Contains("感冒", p.History);
            Assert.DoesNotContain("心脏病", p.History);

            //Predicate
            //对集合中的元素判断是否包含
            Assert.Contains(p.History, x => x.StartsWith("水"));
            //对集合内的所有元素都进行判断
            Assert.All(p.History, x => Assert.True(x.Length >= 2));


            // 判断两个集合是否相等

            var diseases = new List<string>
            {
                "感冒",
                "发烧",
                "水痘",
                "腹泻"
            };
            Assert.Equal(p.History, diseases);
        }

        // 对  object 进行测试
        [Fact]
        public void BeAPerson()
        {
            var p1 = new patient();
            var p2 = new patient();
            Assert.IsType<patient>(p1);//p是否是 patient 类型.
            Assert.IsNotType<Person>(p1);//这个就会判断处所。尽管是他的子类.
            Assert.IsAssignableFrom<Person>(p1);//判断是否继承于某个类

            //判断是否是一个实例
            //same 是同一个实例
            Assert.NotSame(p1,p2);
            // Assert.Same(p1,p2);
         }

        // 判断异常
        // 判断抛出的异常是否和我们所期待的相等.
        // 对委托和事件的测试.
        // 写起来有点麻烦,用到再说吧。
    }

5.数据驱动测试

举例前边的,加法的测试,可以写多个 fact,但是比较麻烦,使用【Theory】+ 【InlineData】有简单的方法。

 public  class Theory_CaculatorTest
    {
        [Theory]
        [InlineData(1,2,3)]
        [InlineData(1, 3, 4)]
        [InlineData(2, 2, 4)]
        [InlineData(1, 9, 10)]
        [InlineData(9, 2, 11)]

        public void ShouldAddEquls(int x, int y, int expected)
        {
            var sut = new Cakulator();
            var reslut = sut.Add(x,y);
            Assert.Equal(expected,reslut);
        }
    }

除此之外,还可以直接用 从数据库或者 CSV等文件中读取后进行测试,这里没看,用到的时候再学吧

题外话

最大的是解决方案名,下边是类名

参考文献:
xUnit.Net单元测试
gitee代码

posted @ 2020-08-18 14:49  沧海一声笑rush  阅读(89)  评论(0编辑  收藏  举报