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

  • 时间:
  • 浏览:0
  • 来源:大发uu快3_uu快3登录_大发uu快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层有变动,则时要显式修改测试土法子,不不利于维护,只是这种 土法子是都都上能通用的.一旦创建好前一天前一天遇到那么 的业务就都都上能直接调用了.