.net测试篇之测试神器Autofixture Generator使用与自定义builder

  • 时间:
  • 浏览:0

系列目录

有了上一节自定义配置,统统什么的问题都能外理了,怎样才能让怎样才能让仅仅是为了外理有另4个 简单什么的问题只能 创建有另4个 类显得很糙繁重.觉得AutoFixture在创建Fixture对象时有统统方便的Fluent配置,亲戚亲戚大伙儿这里介绍一点比较常用了.

创建对象是忽略一点属性

一点完后 有只能 的一点业务场景,一点字段是非必填项,怎样才能让一旦填写则需用符合指定规则.哪些地方地方非必填字段在业务中仅仅当它占据 的完后 做一点校验,其它地方并只能 使用到它.只能 在单元测试的完后 亲戚亲戚大伙儿为了下行时延 还需用暂时忽略哪些地方地方字段.在底下集成测试的完后 再提供完正数据.

下面看看AutoFixture在生成对象的完后 怎样才能显式地忽略一点字段

觉得要忽略是怎样才能让怎样才能让不忽略AutoFixture自动为字符串类型生成有另4个 guid字符串,这怎样才能让导致 验证失败.

亲戚亲戚大伙儿扩展一下Person类,代码如下

public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime BirthDay { get; set; }
        public string Mobile { get; set; }
        public string IDCardNo { get; set; }
        public string Email { get; set; }
    }

亲戚亲戚大伙儿看配置代码

       [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();

            var psn = fix.Build<Person>().
                Without(a => a.IDCardNo).
                Create();
        }

这里fix对象使用Build最好的办法,生成有另4个 自定义生成对象,然后该出先统统自定义配置最好的办法,亲戚亲戚大伙儿使用without最好的办法指示AutoFixture在生成时不生成某一字段,有另4个 without底下还还需用再接有另4个 ,怎样才能让需用忽略其它字段,还需用串联使用多个without.

指定当前时间

在集成测试的完后 ,一点关于时间的字段都需统统当前时间,这完后 还需用使用AutoFixture内置的自定义类CurrentDateTimeGenerator来实现

 [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new CurrentDateTimeGenerator());
            var psn = fix.Create<Person>();
        }

[info]当然以上配置怎样才能让是只能 必要的,怎样才能让C#很早就支持属性赋初值了.

UriGenerator

此配置还需用让AutoFixture生成有另4个 Uri

```cs

[Test]

public void FixValueTest()

{

var fix = new Fixture();

fix.Customizations.Add(new UriGenerator());

var br = fix.Create()# AutoFixture配置二

有了上一节自定义配置,统统什么的问题都能外理了,怎样才能让怎样才能让仅仅是为了外理有另4个 简单什么的问题只能 创建有另4个 类显得很糙繁重.觉得AutoFixture在创建Fixture对象时有统统方便的Fluent配置,亲戚亲戚大伙儿这里介绍一点比较常用了.

创建对象是忽略一点属性

一点完后 有只能 的一点业务场景,一点字段是非必填项,怎样才能让一旦填写则需用符合指定规则.哪些地方地方非必填字段在业务中仅仅当它占据 的完后 做一点校验,其它地方并只能 使用到它.只能 在单元测试的完后 亲戚亲戚大伙儿为了下行时延 还需用暂时忽略哪些地方地方字段.在底下集成测试的完后 再提供完正数据.

下面看看AutoFixture在生成对象的完后 怎样才能显式地忽略一点字段

觉得要忽略是怎样才能让怎样才能让不忽略AutoFixture自动为字符串类型生成有另4个 guid字符串,这怎样才能让导致 验证失败.

亲戚亲戚大伙儿扩展一下Person类,代码如下

public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime BirthDay { get; set; }
        public string Mobile { get; set; }
        public string IDCardNo { get; set; }
        public string Email { get; set; }
    }

亲戚亲戚大伙儿看配置代码

       [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();

            var psn = fix.Build<Person>().
                Without(a => a.IDCardNo).
                Create();
        }

这里fix对象使用Build最好的办法,生成有另4个 自定义生成对象,然后该出先统统自定义配置最好的办法,亲戚亲戚大伙儿使用without最好的办法指示AutoFixture在生成时不生成某一字段,有另4个 without底下还还需用再接有另4个 ,怎样才能让需用忽略其它字段,还需用串联使用多个without.

指定当前时间

在集成测试的完后 ,一点关于时间的字段都需统统当前时间,这完后 还需用使用AutoFixture内置的自定义类CurrentDateTimeGenerator来实现

 [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new CurrentDateTimeGenerator());
            var psn = fix.Create<Person>();
        }

[info]当然以上配置怎样才能让是只能 必要的,怎样才能让C#很早就支持属性赋初值了.

UriGenerator

此配置还需用让AutoFixture生成有另4个 Uri

 [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new UriGenerator());
            var br = fix.Create<Uri>();
        }

MailAddressGenerator

用于生成邮箱地址

 [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new MailAddressGenerator());
            var mr = fix.Create<MailAddress>()
        }

当然统统完后 亲戚亲戚大伙儿是后该MailAddress里的字符串.这完后 使用MailAddress的Address属性即可.

;

}

```

MailAddressGenerator

用于生成邮箱地址

 [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new MailAddressGenerator());
            var mr = fix.Create<MailAddress>()
        }

当然统统完后 亲戚亲戚大伙儿是后该MailAddress里的字符串.这完后 使用MailAddress的Address属性即可.

AutoFixture结合DataAnnotations

一点完后 有只能 一点场影,亲戚亲戚大伙儿的实体类饱含统统验证注解,这就对制造出者的假数据有统统要求,比如需用符合邮箱号,身份证号,字符串长度需用为特定值,手机号需用为特定长度数字等等.通过前面讲到的自定义配置亲戚亲戚大伙儿还需用实现以上功能,怎样才能让怎样才能让仅仅是为了生成有另4个 指定长度的字符串亲戚亲戚大伙儿再新建有另4个 配置类觉得很糙繁琐,怎样才能让哪些地方地方逻辑统统要后该通用的.更为繁杂的是有完后 有另4个 特定字段需用符合某一正则规则,怎样才能后该你你这种 规则非常繁杂后该生成满足它的假数据觉得需至少 些心思,这完后 怎样才能让AutoFixture能自动生成满足条件的假数据那该有好多,实际上AutoFixture觉得还需用生成满足DataAnnotations约束的字段,怎样才能让不需用配置默认统统支持的.

比如现在Person类改为如下:

public class Person{
        [StringLength(10)]
        public string Name { get; set; }
        [Range(18,42)]
        public int Age { get; set; }
        public DateTime BirthDay { get; set; }
        [RegularExpression("\\d{11}")]
        public string Mobile { get; set; }
}

AutoFixture会自动生成满足条件的字段.

AutoFixture 生成符合特定业务的字段.

Attribute自动生成符合注解约束的字段为集成测试提供了很大方便.然而一点功能不论是注解还是AutoFixture内置的配置都无法完成,这完后 就需用自定义的配置.

比如说有以下业务场景,一点业务模型饱含开始 时间和开始 时间,这里后该有另4个 隐性约束统统开始 时间需用大于怎样才能让等于开始 时间,怎样才能让后该只能 数据库中就无法取到值.你你你这种 完后 就需用使用自定义配置了.

比如有一下模型:

 public class CustomDate
    {
        public DateTime StartTime { get; set; }
        public DateTime EndTime { get; set; }
    }

[info]这里统统有另4个 普通例子,统统完后 业务底下后该只能 的模型,怎样才能让要让开始 时间晚于开始 时间,亲戚亲戚大伙儿首不难 先取舍哪个时开始 时间,哪个是开始 时间,这里亲戚亲戚大伙儿使用基于命名约束的最好的办法来取舍它们:即开始 时间饱含start,开始 时间饱含end(当然也还需用是其它标识,假若能取舍它们即可).当然这并后该有一种很好的设计.理想的情况表下是对字段进行注解,怎样才能让仅仅为了测试而去扩展现有项目的做法也是值得商榷的.

以下为自定义最好的办法

 public class DateTimeSpecimenBuilder:ISpecimenBuilder
    {
        private readonly Random _random = new Random();
        private DateTime startDate = DateTime.Now;
        public object Create(object request, ISpecimenContext context)
        {
            var pi = request as PropertyInfo;
            if (pi != null && pi.Name.ToLower().Contains("start") &&
                (pi.PropertyType == typeof(DateTime) || pi.PropertyType == typeof(DateTime?)))
            {
               
                var stDate = context.Create<DateTime>();
                
                startDate =stDate ;
                return startDate;
            }

            if (pi != null && pi.Name.ToLower().Contains("end") &&
                (pi.PropertyType == typeof(DateTime) || pi.PropertyType == typeof(DateTime?)))
            {
                var endDate = startDate.AddDays(_random.Next(1,20));
                return endDate;
            }
            return new NoSpecimen();
        }
    }
        [Test]
        public void FixValueTest()
        {
            var fix = new Fixture();
            fix.Customizations.Add(new DateTimeSpecimenBuilder());
            var customDate = fix.Create<CustomDate>();
        }

简单梳理一下以上代码,基本逻辑统统怎样才能让传入字段饱含start关键型态怎样才能让是日期类型,亲戚亲戚大伙儿就把它的值存起来,当底下遇到饱含end型态的属性时就把刚才存入的值再添加指定天数只能 就能保证enddate大于startdate了.

生成引用类型时指定构造函数

当有另4个 类有多个构造函数时,AutoFixture默认使用参数至少 的构造函数来构造有另4个 对象,怎样才能让这在一点完后 会造成麻烦:有另4个 Bll类怎样才能让有多个构造函数,构造函数里传入的是依赖对象,怎样才能让只调用参数至少 的构造函数则统统依赖无法传入,只能 怎样才能让使用到了依赖对象就会报Null引用异常.你你你这种 完后 亲戚亲戚大伙儿就需用显式的指定调用哪有另4个 构造函数.

亲戚亲戚大伙儿仍然通过示例来讲解.

亲戚亲戚大伙儿把Person类改成如下:

public class Person
    {
        public Person(string name)
        {
            Name = name;
        }

        public Person(string name,int age)
        {
            Age = age;
            Name = name;
        }
        [StringLength(10)]
        public string Name { get; set; }
        [Range(18,42)]
        public int Age { get; set; }
        public DateTime BirthDay { get; set; }
        [RegularExpression("\\d{11}")]
        public string Mobile { get; set; }
        public string IDCardNo { get; set; }

与完后 相比,你你你这种 类多了有另4个 有参构造函数.

注意,即使类型不饱含无参构造函数,AutoFixture依然不需要后该 创建它,统统使用哪个构造函数是不取舍的.

要实现让AutoFixture取舍亲戚亲戚大伙儿后该的构造函数,亲戚亲戚大伙儿创建有另4个 实现了IMethodQuery的类型,怎样才能让添加到配置里.

你你你这种 类代码如下

 public class MyMethodSelector : IMethodQuery
    {
        private readonly Type[] _types;

        public MyMethodSelector(params Type[] type)
        {
            _types = type;
        }

        public IEnumerable<IMethod> SelectMethods(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException();
            }

            var constructors = type
                .GetConstructors().Where(a => a.GetParameters().Select(t => t.ParameterType).SequenceEqual(_types))
                .Select(a => new ConstructorMethod(a));

            return constructors;
        }
    }

亲戚亲戚大伙儿来分析一下这段代码,首先亲戚亲戚大伙儿在构造函数里传入type 数组,这里的type为构造函数参数的类型.SelectMethods为接口提供的最好的办法,你你你这种 最好的办法接收有另4个 type类型作为参数,你你你这种 type为操作的对象的类型.怎样才能让亲戚亲戚大伙儿使用GetConstructors最好的办法获取它所有的构造函数.怎样才能让通过Where过滤符合条件的(条件是参数的类型和构造函数传入的类型一样).怎样才能让亲戚亲戚大伙儿使用过滤后的Constructorinfo来创建有另4个 ConstructorMethod,ConstructorMethod为AutoFixture提供的有另4个 类型.

下面是测试代码

var fix = new Fixture();
            fix.Customize(new ConstructorCustomization(typeof(Person),
                new MyMethodSelector(typeof(string), typeof(int))));
            var psn = fix.Create<Person>();

这里亲戚亲戚大伙儿给MyMethodSelector传入了有另4个 类型,分别是string类型和int类型,以期望AutoFixture调用饱含string和int参数的构造最好的办法.亲戚亲戚大伙儿启用调试模式,就还需用想看 Person的第好几个 构造函数被调用了.

想看 这里,统统人怎样才能让会感觉一点厌烦,感觉只能 做还不如直接New有另4个 对象,在new的完后 显式调用特定的构造函数就不需要有只能 麻烦了.关于直接new对象的缺点前面也说过,怎样才能让Bll层有变动,则需用显式修改测试最好的办法,不助于维护,怎样才能后该你你这种 最好的办法是还需用通用的.一旦创建好完后 完后 遇到只能 的业务就还需用直接调用了.