xUnit单元测试

2,293 阅读2分钟
       xUnit支持两种不同类型的单元测试,事实[Fact]和理论[Theory]。 当我们无论数据怎样变化总有一些标准总是必须符合时我们使用xUnit Fact。 例如,当我们测试一个业务流程。 而xUnit理论依赖于一组参数及其数据,我们将参数和数据传递给测试方法, 我们根据特定数据来判断测试结果时我们使用xUnit Theory。xUnit Theory 支持3种数据传递方式InlineData、MemberData 和 ClassData。

  InlineData

      我们使用Fact一般是这样:

        [Fact]
        public void TestAdd()
        {
            Assert.Equal(5, Add(2, 3));
            Assert.Equal(7, Add(2, 5));
            Assert.Equal(10, Add(4, 6));
        }

       多个数据的话代码重复,那么使用InlineData则变成了这样:

        [Theory]
        [InlineData(5, 2, 3)]
        [InlineData(7, 2, 5)]
        [InlineData(10, 5, 5)]
        public void TestAddUseInlineData(int sum, int a, int b)
        {
            Assert.Equal(sum, Add(a, b));
        }

        正如上面的代码,我们在InlineData中提供了一些值,xUnit将创建多个测试,并且每次都将测试用例参数填充到InlineData中。 但是InlineData属性中传递有很多限制,只能传递简单类型,我们如果想要传递更复杂的参数可以使用MemberData 和 ClassData。

ClassData

         ClassData是Theory的第二种传递参数的方式,虽然更复杂但是传递时也更方便。以下示例是一个测试判断用户是否输入了手机号码的方法

    public class TestsUseClassData
    {
        public bool HasMobile(Person person)
        {
            return !string.IsNullOrWhiteSpace(person.Mobile);
        }

        [Theory]
        [ClassData(typeof(DataForTest))]//使用ClassData将数据传递给Theory
        public void IndexOf(Person person, bool hasMobile)
        {
            Assert.Equal(hasMobile, HasMobile(person));
        }
    }

    /// <summary>
    /// 在这里我创建了一个继承自IEnumerable <object []>的类,注意它必须是一个对象,
    /// 否则xUnit会抛出一个错误。
    /// </summary>
    public class DataForTest : IEnumerable<object[]>
    {
        //这里是我们传递给Theory的数据
        private readonly List<object[]> _data = new List<object[]>
    {
        new object[] { new Person() { Id=1,Name="周三"},false },
        new object[] { new Person() { Id=2,Name="王石", Mobile = "139XXXXXXXX"},true },
        new object[] { new Person() { Id=3,Name="赵坎", Mobile = ""},false },
    };

        public IEnumerator<object[]> GetEnumerator()
        { return _data.GetEnumerator(); }

        IEnumerator IEnumerable.GetEnumerator()
        { return GetEnumerator(); }
    }

    public class Person
    {
        public int Id { get; set; }

        public string Name { get; set; }

        public string Mobile { get; set; }
    }

          您可以实际跑跑上面的代码,下面我们看看MemberData的使用。

MemberData

          MemberData同样可以传递复杂类型参数,而且我们不必创建一个类来承载它,示例如下:

    public class TestsUseMemberData
    {
        public bool HasMobile(Person person)
        {
            return !string.IsNullOrWhiteSpace(person.Mobile);
        }

        //传递数据给Theory的方法
        public static IEnumerable<object[]> GetTestData()
        {
            yield return new object[] { new Person() { Id = 1, Name = "周三" }, false };
            yield return new object[] { new Person() { Id = 2, Name = "王石", Mobile = "139XXXXXXXX" }, true };
            yield return new object[] { new Person() { Id = 3, Name = "赵坎", Mobile = "" }, false };
        }


        [Theory]
        [MemberData(nameof(GetTestData))]//使用MemberData将数据传递给Theory
        public void IndexOf(Person person, bool hasMobile)
        {
            Assert.Equal(hasMobile, HasMobile(person));
        }
    }