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

  • 时间:
  • 浏览:0
  • 来源:极速快3_快3下载网址_极速快3下载网址

系列目录

有了上一节自定义配置,好多好多 难题都能解决了,有刚刚 刚刚仅仅是为了解决八个 多 简单难题如此创建八个 多 类显得很重繁重.人太好AutoFixture在创建Fixture对象时有好多好多 方便的Fluent配置,大伙这里介绍有刚刚 比较常用了.

创建对象是忽略有刚刚 属性

有刚刚 刚刚有原本 的有刚刚 业务场景,有刚刚 字段是非必填项,有刚刚 一旦填写则都可否 符合指定规则.那先 非必填字段在业务中仅仅当它存在的刚刚做有刚刚 校验,其它地方并如此使用到它.原本 在单元测试的刚刚大伙为了波特率都可否 暂时忽略那先 字段.在上方集成测试的刚刚再提供完整篇 数据.

下面看看AutoFixture在生成对象的刚刚咋样显式地忽略有刚刚 字段

固然要忽略是刚刚刚刚不忽略AutoFixture自动为字符串类型生成八个 多 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措施 ,生成八个 多 自定义生成对象,然不会总出 好多好多 自定义配置措施 ,大伙使用without措施 指示AutoFixture在生成时不生成某一字段,八个 多 without上方都可否 再接八个 多 ,刚刚都可否 忽略其它字段,都可否 串联使用多个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生成八个 多 Uri

```cs

[Test]

public void FixValueTest()

{

var fix = new Fixture();

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

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

有了上一节自定义配置,好多好多 难题都能解决了,有刚刚 刚刚仅仅是为了解决八个 多 简单难题如此创建八个 多 类显得很重繁重.人太好AutoFixture在创建Fixture对象时有好多好多 方便的Fluent配置,大伙这里介绍有刚刚 比较常用了.

创建对象是忽略有刚刚 属性

有刚刚 刚刚有原本 的有刚刚 业务场景,有刚刚 字段是非必填项,有刚刚 一旦填写则都可否 符合指定规则.那先 非必填字段在业务中仅仅当它存在的刚刚做有刚刚 校验,其它地方并如此使用到它.原本 在单元测试的刚刚大伙为了波特率都可否 暂时忽略那先 字段.在上方集成测试的刚刚再提供完整篇 数据.

下面看看AutoFixture在生成对象的刚刚咋样显式地忽略有刚刚 字段

固然要忽略是刚刚刚刚不忽略AutoFixture自动为字符串类型生成八个 多 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措施 ,生成八个 多 自定义生成对象,然不会总出 好多好多 自定义配置措施 ,大伙使用without措施 指示AutoFixture在生成时不生成某一字段,八个 多 without上方都可否 再接八个 多 ,刚刚都可否 忽略其它字段,都可否 串联使用多个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生成八个 多 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

有刚刚 刚刚有原本 有刚刚 场影,大伙的实体类涵盖好多好多 验证注解,这就对制科学发明的假数据有好多好多 要求,比如都可否 符合邮箱号,身份证号,字符串长度都可否 为特定值,手机号都可否 为特定长度数字等等.通过前面讲到的自定义配置大伙都可否 实现以上功能,有刚刚 刚刚仅仅是为了生成八个 多 指定长度的字符串大伙再新建八个 多 配置类人太好很重繁琐,有刚刚 那先 逻辑好多好多 必完整篇 不会通用的.更为繁复的是有刚刚八个 多 特定字段都可否 符合某一正则规则,刚刚你你你一种生活规则非常繁复你都可否 生成满足它的假数据人太好需要花费些心思,这刚刚刚刚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内置的配置都无法完成,这刚刚就都可否 自定义的配置.

比如说有以下业务场景,有刚刚 业务模型涵盖刚刚刚刚刚刚开使时间和刚刚刚刚刚开使时间,这里就八个 多 隐性约束好多好多 刚刚刚刚刚开使时间都可否 大于刚刚等于刚刚刚刚刚刚开使时间,刚刚完整篇 不会原本 数据库中就无法取到值.你你你一种生活刚刚就都可否 使用自定义配置了.

比如有一下模型:

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

[info]这里好多好多 八个 多 普通例子,好多好多 刚刚业务上方完整篇 不会原本 的模型,刚刚要让刚刚刚刚刚开使时间晚于刚刚刚刚刚刚开使时间,大伙首如此先选泽哪个时刚刚刚刚刚刚开使时间,哪个是刚刚刚刚刚开使时间,这里大伙使用基于命名约束的措施 来选泽它们:即刚刚刚刚刚刚开使时间涵盖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了.

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

当八个 多 类有多个构造函数时,AutoFixture默认使用参数要花费的构造函数来构造八个 多 对象,有刚刚 这在有刚刚 刚刚会造成麻烦:八个 多 Bll类刚刚有多个构造函数,构造函数里传入的是依赖对象,刚刚只调用参数要花费的构造函数则好多好多 依赖无法传入,原本 刚刚使用到了依赖对象就会报Null引用异常.你你你一种生活刚刚大伙就都可否 显式的指定调用哪八个 多 构造函数.

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

大伙把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; }

与刚刚相比,你你你一种生活类多了八个 多 有参构造函数.

注意,即使类型不涵盖无参构造函数,AutoFixture依然都可否创建它,好多好多 使用哪个构造函数是不选泽的.

要实现让AutoFixture选泽大伙你都可否 的构造函数,大伙创建八个 多 实现了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为接口提供的措施 ,你你你一种生活措施 接收八个 多 type类型作为参数,你你你一种生活type为操作的对象的类型.有刚刚 大伙使用GetConstructors措施 获取它所有的构造函数.有刚刚 通过Where过滤符合条件的(条件是参数的类型和构造函数传入的类型一样).有刚刚 大伙使用过滤后的Constructorinfo来创建八个 多 ConstructorMethod,ConstructorMethod为AutoFixture提供的八个 多 类型.

下面是测试代码

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

这里大伙给MyMethodSelector传入了八个 多 类型,分别是string类型和int类型,以期望AutoFixture调用涵盖string和int参数的构造措施 .大伙启用调试模式,就都可否 看多Person的第八个构造函数被调用了.

看多这里,好多好多 人刚刚会感觉有刚刚 厌烦,感觉原本 做还不如直接New八个 多 对象,在new的刚刚显式调用特定的构造函数就很多有如此麻烦了.关于直接new对象的缺点前面也说过,刚刚Bll层有变动,则都可否 显式修改测试措施 ,不促使维护,有刚刚 你你你一种生活措施 是都可否 通用的.一旦创建好刚刚刚刚遇到原本 的业务就都可否 直接调用了.