zoukankan      html  css  js  c++  java
  • 单元测试实践

    前言

    在此,只是对下面这条链接的实现:

    https://www.cnblogs.com/AlexanderZhao/p/12369732.html

    正文

    测试分类:

    1.单元测试

    2.集成测试

    3.皮下测试

    4.UI测试

    测试的三个阶段:AAA

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

    Assert方法应用

    bool 值:

    Patient patient = new Patient();
    var result = patient.IsNew;
    Assert.True(result);
    Assert.False(result);
    

    string 类型:

    [Fact]
    public async void Test1()
    {
    	Patient patient = new Patient();
    	Assert.Equal("xxx",patient.FistName);
    	Assert.NotEqual("xxx",patient.LastName);
    	Assert.StartsWith("xxx",patient.LastName);
    	Assert.EndsWith("xxx",patient.LastName);
    	Assert.Contains("xxx",patient.LastName);
    	Assert.Matches(@"xxx",patient.LastName);
    }
    

    数字类型:

    Patient patient = new Patient();
    var result = patient.Age;
    Assert.Equal(4.9f,result);
    Assert.InRange(result,3.9,6.1);
    

    判断null 和 not null

    var p = new Patient();
    Assert.Null(p.FirstName);
    Assert.NotNull(_patient);
    

    集合:

    Patient patient = new Patient();
    var diseases = new List<string>
    {
    	"感冒",
    	"发烧",
    	"水痘",
    	"腹泻"
    };
    Assert.Contains("感冒",patient.History);
    Assert.DoesNotContain("感冒", patient.History);
    // any
    Assert.Contains(patient.History,x=>x.StartsWith("水"));
    // 遍历 all
    Assert.All(patient.History, x => { Assert.True(x.Length > 2); });
    Assert.Equal(diseases,patient.History);
    

    对象:

    Patient patient = new Patient();
    Patient patient1 = new Patient();
    // 类型是否相同
    Assert.IsNotType<Patient>(patient);
    Assert.IsType<Patient>(patient);
    // 两个实例是否是同一个
    Assert.Same(patient,patient1);
    Assert.NotSame(patient, patient1);
    //是否继承Patient
    Assert.IsAssignableFrom<Patient>(patient);
    

    错误性验证:

    Patient patient = new Patient();
    // 判断是否出现指定的异常
    var ex = Assert.Throws<InvalidOperationException>(()=> { patient.NotAllowed(); });
    // 进一步判断异常消息
    Assert.Equal("not able to create", ex.Message);
    

    判断是否触发事件:

    /// <summary>
    /// 判断是否触发事件
    /// </summary>
    [Fact]
    public void RaizeSleepEvent()
    {
        var p = new Patient();
        Assert.Raises<EventArgs>(
            handler=>p.PatientSlept+=handler,
            handler=>p.PatientSlept -= handler,
            () => p.Sleep());
    }
    

    判断属性改变是否触发事件#

    /// <summary>
    /// 测试属性改变事件是否触发
    /// </summary>
    [Fact]
    public void RaisePropertyChangedEvent()
    {
        var p = new Patient();
        Assert.PropertyChanged(p, nameof(p.HeartBeatRate),
                               () => p.IncreaseHeartBeatRate());
    }
    

    进阶

    分组测试:

    [Fact]
    [Trait("Category", "New")]
    public void BeNewWhenCreated()
    {
    	var patient = new Patient();
    	patient.IsNew = true;
    	var result = patient.IsNew;
    	Assert.True(result);
    }
    
    [Fact]
    [Trait("Category", "add")]
    public void BeNewWhenCreated1()
    {
    	var patient = new Patient();
    	var result = patient.IsNew;
    	Assert.True(result);;
    }
    
    dotnet test --filter “Category=New” //运行单个分类测试
    dotnet test --filter “Category=New|Category=Add”//运行多个分类测试
    dotnet test --filter Category --logger:trx //输出测试日志
    

    忽略测试#

    使用特性:[Fact(Skip="不跑这个测试")],可以忽略测试,忽略测试图标为黄色警告

    自定义测试输出内容#

    使用ITestOutputHelper可以自定义在测试时的输出内容
    dotnet test --filter Category --logger:trx会输出测试日志trx结尾的文件

    public class PatientShould:IClassFixture<LongTimeFixture>,IDisposable
    {
        private readonly ITestOutputHelper _output;
        private readonly Patient _patient;
        private readonly LongTimeTask _task;
        public PatientShould(ITestOutputHelper output,LongTimeFixture fixture)
        {
            this._output = output;
            _patient = new Patient();
            //_task = new LongTimeTask();
            _task = fixture.Task;
        }
    
        [Fact]
        [Trait("Category","New")]
        public void BeNewWhenCreated()
        {
            _output.WriteLine("第一个测试");
            // Arrange
            //var patient = new Patient();
            // Act
            var result = _patient.IsNew;
            // Assert
            Assert.True(result);
            //Assert.False(result);
        }
    }
    

    减少重复代码#

    减少new对象,可以在构造函数中new,在方法中使用。
    测试类实现IDispose接口,测试完释放资源,注意每个测试结束后都会调用Dispose方法。
    

    共享上下文#
    同一个测试类#

    在执行一个方法时,需要很长事件,而在构造函数中new时,每个测试跑的时候都会new对象或者执行方法,这是导致测试很慢。解决方法:

    创建一个类:

    using Demo2;
    using System;
    
    namespace Demo2Test
    {
        public class LongTimeFixture : IDisposable
        {
            public LongTimeTask Task { get; }
            public LongTimeFixture()
            {
    
            }
            public void Dispose()
            {
            }
        }
    }
    

    测试类实现IClassFixture接口,并在构造函数中获取方法

    public class PatientShould:IClassFixture<LongTimeFixture>,IDisposable
    {
        private readonly ITestOutputHelper _output;
        private readonly Patient _patient;
        private readonly LongTimeTask _task;
        public PatientShould(ITestOutputHelper output,LongTimeFixture fixture)
        {
            this._output = output;
            _patient = new Patient();
            //_task = new LongTimeTask();
            _task = fixture.Task;//获取方法
        }
    }
    

    不同的测试类#

    1.在上一个的继承上,先建立一个TaskCollection类,实现ICollectionFixture接口,注意不能有副作用,否则会影响结果

    using Xunit;
    
    namespace Demo2Test
    {
        [CollectionDefinition("Lone Time Task Collection")]
        public class TaskCollection:ICollectionFixture<LongTimeFixture>
        {
        }
    }
    

    使用,加上[Collection("Lone Time Task Collection")]

    [Collection("Lone Time Task Collection")]
    public class PatientShould:IClassFixture<LongTimeFixture>,IDisposable
    {
        private readonly ITestOutputHelper _output;
        private readonly Patient _patient;
        private readonly LongTimeTask _task;
        public PatientShould(ITestOutputHelper output,LongTimeFixture fixture)
        {
            this._output = output;
            _patient = new Patient();
            //_task = new LongTimeTask();
            _task = fixture.Task;//获取方法
        }
    }
    

    数据共享

    1. 使用[Theory],可以写有构造参数的测试方法,使用InlineData传递数据#
    [Theory]
    [InlineData(1,2,3)]
    [InlineData(2,2,4)]
    [InlineData(3,3,6)]
    public void ShouldAddEquals(int operand1,int operand2,int expected)
    {
        //Arrange
        var sut = new Calculator(); //sut-system under test
        //Act
        var result = sut.Add(operand1, operand2);
        //Assert
        Assert.Equal(expected, result);
    }
    

    2. 使用[MemberData]特性,可以在多个测试中使用#

    先添加CalculatorTestData类:

    using System.Collections.Generic;
    
    namespace DemoTest
    {
        public  class CalculatorTestData
        {
            private static readonly List<object[]> Data = new List<object[]>
            {
                new object[]{ 1,2,3},
                new object[]{ 1,3,4},
                new object[]{ 2,4,6},
                new object[]{ 0,1,1},
            };
    
            public static IEnumerable<object[]> TestData => Data;
        }
    }
    

    使用MemberData

    /// <summary>
    /// 数据共享-MemberData
    /// </summary>
    /// <param name="operand1"></param>
    /// <param name="operand2"></param>
    /// <param name="expected"></param>
    [Theory]
    [MemberData(nameof(CalculatorTestData.TestData),MemberType =typeof(CalculatorTestData))]
    public void ShouldAddEquals2(int operand1, int operand2, int expected)
    {
        //Arrange
        var sut = new Calculator(); //sut-system under test
        //Act
        var result = sut.Add(operand1, operand2);
        //Assert
        Assert.Equal(expected, result);
    }
    

    3. 使用外部数据

    先创建一个类,准备数据,这里是读取的csv文件的数据
    
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    
    namespace DemoTest.Data
    {
        /// <summary>
        /// 读取文件并返回数据集合
        /// </summary>
        public class CalculatorCsvData
        {
            public static IEnumerable<object[]> TestData
            {
                get
                {
    	            //把csv文件中的数据读出来,转换
                    string[] csvLines = File.ReadAllLines("Data\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;
                }
            }
        }
    }
    

    2.csv数据

    Copy
    1,2,3
    1,3,4
    2,4,6
    0,1,1

    /// <summary>
    /// 数据共享-MemberData-外部数据
    /// </summary>
    /// <param name="operand1"></param>
    /// <param name="operand2"></param>
    /// <param name="expected"></param>
    [Theory]
    [MemberData(nameof(CalculatorCsvData.TestData), MemberType = typeof(CalculatorCsvData))]
    public void ShouldAddEquals3(int operand1, int operand2, int expected)
    {
        //Arrange
        var sut = new Calculator(); //sut-system under test
        //Act
        var result = sut.Add(operand1, operand2);
        //Assert
        Assert.Equal(expected, result);
    }
    
    1. 使用自定义特性,继承自DataAttribute#

      自定义特性

    using System.Collections.Generic;
    using System.Reflection;
    using Xunit.Sdk;
    
    namespace DemoTest.Data
    {
        public class CalculatorDataAttribute : DataAttribute
        {
            public override IEnumerable<object[]> GetData(MethodInfo testMethod)
            {
                yield return new object[] { 0, 100, 100 };
                yield return new object[] { 1, 99, 100 };
                yield return new object[] { 2, 98, 100 };
                yield return new object[] { 3, 97, 100 };
            }
        }
    }
    
    /// <summary>
    /// 数据共享-自定义特性继承自DataAttribute
    /// </summary>
    /// <param name="operand1"></param>
    /// <param name="operand2"></param>
    /// <param name="expected"></param>
    [Theory]
    [CalculatorDataAttribute]
    public void ShouldAddEquals4(int operand1, int operand2, int expected)
    {
        //Arrange
        var sut = new Calculator(); //sut-system under test
        //Act
        var result = sut.Add(operand1, operand2);
        //Assert
        Assert.Equal(expected, result);
    }
    
  • 相关阅读:
    java基础---->摘要算法的介绍
    startActivityForResult的用法和demo
    Java 获取类名,函数名,行数
    android ListView详解继承ListActivity
    Java List 如何传值
    synchronized的使用方法
    StringUtil
    【转】Java 5种字符串拼接方式性能比较。
    [Android] Intent详解
    TabHost详解
  • 原文地址:https://www.cnblogs.com/aoximin/p/12704317.html
Copyright © 2011-2022 走看看