首页 > 其他分享 >.NET单元测试使用AutoFixture按需填充属性的几种方式,以及最佳实践

.NET单元测试使用AutoFixture按需填充属性的几种方式,以及最佳实践

时间:2024-07-19 14:42:29浏览次数:9  
标签:单元测试 fixture user var new NET AutoFixture public

AutoFixture是一个.NET库,旨在简化单元测试中的数据设置过程。通过自动生成测试数据,它帮助开发者减少测试代码的编写量,使得单元测试更加简洁、易读和易维护。AutoFixture可以用于任何.NET测试框架,如xUnit、NUnit或MSTest。

默认情况下AutoFixture生成的字段值很多时候都满足不了测试需求,比如:

public class User
{
	public int Id { get; set; }
	public string Name { get; set; } = null!;
	[EmailAddress]
	public string? Email { get; set; }
	[StringLength(512)]
	public string? Address { get; set; }
	public DateTime CreatedAt { get; set; } = DateTime.Now;
}

如果直接使用 Create<T>()生成的User对象,他会默认给你填充Id为随机整数,Name和Email为一串Guid,显然这里的邮箱地址生成就不能满足要求,并不是一个有效的邮箱格式

那么如何让AutoFixture按需生成有效的测试数据呢?方法其实有好几种:

方法1:直接定制
var fixture = new Fixture();
fixture.Customize<User>(c => c
    .With(x => x.Email, "特定值")
    .Without(x => x.Id));

这里,With方法用于指定属性的具体值,而Without方法用于排除某些属性不被自动填充。

方法2:使用匿名函数

这在需要对生成的数据进行更复杂的操作时非常有用。

var fixture = new Fixture();
fixture.Customize<User>(c => c.FromFactory(() => new User
{
    Email = "通过工厂方法生成",
}));
方法3:实现ICustomization接口

对于更复杂的定制需求,可以通过实现ICustomization接口来创建一个定制化类。这种方法的好处是可以重用定制逻辑,并且使得测试代码更加整洁。

public class MyCustomClassCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<User>(c => c
            .With(x => x.Email, "自定义值")
            .Without(x => x.Id));
    }
}
// 使用定制化
var fixture = new Fixture();
fixture.Customize(new MyCustomClassCustomization());
方法4:使用Build<T>方法

Build<T>方法提供了一种链式调用的方式来定制类型的生成规则,这在只需要对单个对象进行简单定制时非常方便。

var myCustomObject = fixture.Build<User>()
                            .With(x => x.Email, $"{Guid.NewId()}@example.com")
                            .Without(x => x.Id)
                            .Create();

最佳实践:

这里以xunit测试框架为例,
我们需要提前引用AutoFixture,AutoFixture.Xunit2库,实现一个UserAutoDataAttribute类,继承自InlineAutoDataAttribute 重写GetData方法,大致代码如下:

public  class UserAutoDataAttribute : InlineAutoDataAttribute
    {
        public UserAutoDataAttribute(params object[] values) : base(values)
        {
            ArgumentNullException.ThrowIfNull(values[0]);
        }

        public override IEnumerable<object[]> GetData(MethodInfo testMethod)
        {
            var fixture = new Fixture();
            //这里使用上面的4种方式的一种,亦或者根据自身情况定制!
            var user = fixture.Build<User>()
                 //.With(x => x.Id, 0)
                 .Without(x => x.Id) //ID需要排除因为EFCore需要插入时自动生成
                 .With(x => x.Email, $"{Uuid7.NewUuid7()}@example.com") //邮箱地址,需要照规则生成
                 .Create();
            yield return new object[] { Values[0], user };
        }
    }

下面是一个测试用例,需要填充db,和一个自动生成的User参数

public class UnitOfWorkTests(ITestOutputHelper output)
{
	[Theory]
	[UserAutoData(1)]
	[UserAutoData(2)]
	public async Task MyUnitOfWorkTest(int db, User user)
	{
		var services = new ServiceCollection();
		services.AddLogging();
		services.AddDbContext<TestDbContext>(options =>
		 {
                    options.UseInMemoryDatabase($"test-{db}");
		});
		services.AddUnitOfWork<TestDbContext>();

		var provider = services.BuildServiceProvider();
		var uow = provider.GetRequiredService<IUnitOfWork<TestDbContext>>();

		//add user
		await uow.GetRepository<User>().InsertAsync(user);
		await uow.SaveChangesAsync();

		// select user
		var user2 = await uow.GetRepository<User>().FindAsync(1);
		Assert.NotNull(user2);

		// delete user
		uow.GetRepository<User>().Delete(1);
		var row = await uow.SaveChangesAsync();

		Assert.Equal(1, row);

		// select user
		user2 = await uow.GetRepository<User>().GetFirstOrDefaultAsync(x => x.Id == 1);
		Assert.Null(user2);
	}
}

如果你已经习惯编写单元测试,但还没有使用AutoFixture,那么推荐你尝试一下,也许你也会喜欢上TA

标签:单元测试,fixture,user,var,new,NET,AutoFixture,public
From: https://www.cnblogs.com/vipwan/p/18311419

相关文章

  • cad.net HandOverTo替换对象
    在cad.net中有这样一个函数DBObject.HandOverTo();我曾经尝试使用此函数,但是一直报错在经过我的一番查找资料和尝试之后,我发现,此函数无法在StartTransaction()开启事务的上下文中使用我尝试使用OpenCloseTransaction,最终成功完成了替换,代码如下vardoc=Acap.DocumentManage......
  • JSON 格式的字符串反序列化为 .NET 对象
    DeserializeObject是Newtonsoft.Json(通常简称为Json.NET)库中的一个方法,用于将JSON格式的字符串反序列化为.NET对象。这个方法允许你将JSON数据转换成C#中的类实例,使得你可以方便地在程序中操作这些数据。使用方法要使用DeserializeObject方法,你首先需要安装Newton......
  • NET索引器声明
    publicclassMyClass{//假设有一个内部集合或字典来存储数据privateDictionary<string,string>data=newDictionary<string,string>();//索引器声明publicstringthis[stringkey]{get{//返回与给定key相关联的值if(da......
  • 适用于 .NET 的现代化、流畅、可测试的HTTP客户端库
    前言今天大姚给大家分享一个.NET开源(MITLicense)、免费、现代化、流畅、可测试、可移植的URL构建器和HTTP客户端库:Flurl。项目介绍Flurl是一个集现代性、流畅性、异步性、可测试性、可移植性于一身的URL构建器与HTTP客户端库。它提供了简洁的API,使得HTTP请求的发送与URL的构建......
  • NET9 Asp.net Core将整合OpenAPI的文档生成功能而无需三方库
    OpenAPI规范是用于描述HTTPAPI的标准。该标准允许开发人员定义API的形状,这些API可以插入到客户端生成器、服务器生成器、测试工具、文档等中。尽管该标准具有普遍性和普遍性,但ASP.NETCore在框架内默认不提供对OpenAPI的支持。当前ASP.NETCore不提供对OpenAPI......
  • `TypeError: unsupported operand type(s) for +: ‘NoneType‘ and ‘float‘`
    @[TOC](TypeError:unsupportedoperandtype(s)for+:'NoneType'and'float'......
  • .NET|--杂类|--json文件未释放, 就开始反序列化, 报错Newtonsoft.Json Unexpected cha
    前言一个看起来很莫名其妙的错误,json文件我打开看了下,格式也都正确,但是在vs中调试的时候,监视--查看--JSON可视化工具查看json字符串的话,会提示"字符串未设置为JSON格式","监视--查看--文本可视化工具",发现json格式确实看不出来任何问题.报错#报......
  • .NET|--杂类|--将Shp文件转为GeoJson-通过GDAL
    前言真实需求是将Shp转为pbf文件,不过我现在已经实现了,将GeoJson格式数据转换为pbf文件,所以需要实现将Shp文件转换为GeoJson格式即可.1.下载GDAL的程序集下载地址→https://www.gisinternals.com/development.php下载完成,解压zip文件,可以看到这些dll文件(路......
  • Profinet IO从站数据 转EthernetIP项目案例
    目录1 案例说明 12 VFBOX网关工作原理 13 准备工作 24 使用PRONETA软件获取PROFINETIO从站的配置信息 25 设置网关采集PROFINETIO从站设备数据 56 使用ETHERNETIP转发数据 87 选择槽号和数据地址 108 选择子槽号 119 案例总结 121 案例说明设置网关采集ProfinetIO从......
  • NATS: Aspire.NATS.Net 库
    NuGetAspire.NATS.Net快速入门首先,你需要已经配置了NATS服务器,并且知道访问这个服务器的URL地址。安装NuGet使用你熟悉的方式安装NuGet库dotnetaddpackageAspire.NATS.Net使用示例在项目的Program.cs中,调用AddNatsClient()扩展方法以在依赖注入容器中注......