首页 > 其他分享 >.NET单元测试使用AutoFixture

.NET单元测试使用AutoFixture

时间:2024-07-21 13:28:51浏览次数:18  
标签:单元测试 fixture user var new NET AutoFixture public

.NET单元测试使用AutoFixture按需填充的几种方式和最佳实践 

 

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/Leo_wl/p/18314390

相关文章

  • 在.NET Web API设置响应输出Json数据格式常用的两种方式
    前言在ASP.NETCoreWebAPI中设置响应输出Json数据格式常用以下两种方式:可以通过添加System.Text.Json或Newtonsoft.JsonJSON序列化和反序列化库在应用程序中全局设置接口响应的Json数据格式。注意:本文示例使用的是新的MinimalAPI模式。JSON序列化和反序列化库System.Text......
  • .Net知识宣传贴
          此贴仅作为笔者对.Net知识的总结和整理。1、基础知识;(发展历史) .Net的历史2、理论知识;(语法、框架) .Net的语法.Net编码规范.Net基础知识.Net周边框架3、实战知识;(C#、ASP.Net) 4、工具知识;(VS、其它编程工具)编......
  • 适用于 .NET 的现代化、流畅、可测试的HTTP客户端库:Flurl
    适用于.NET的现代化、流畅、可测试的HTTP客户端库:Flurl前言今天大姚给大家分享一个.NET开源(MITLicense)、免费、现代化、流畅、可测试、可移植的URL构建器和HTTP客户端库:Flurl。项目介绍Flurl是一个集现代性、流畅性、异步性、可测试性、可移植性于一身的URL构建器与HTTP客......
  • .NET C# 配置 Options
    .NETC#配置Options使用options模式可以带来许多好处,包括清晰的配置管理、类型安全、易于测试和灵活性。但在使用过程中,也需要注意配置复杂性、性能开销和依赖框架等问题。通过合理设计和使用,可以充分发挥options模式的优势,提高代码的可维护性和可靠性。文章目录......
  • NoneType 在链表中不可下标
    我正在开发一个基本推荐软件的组合项目,其中我收集用户输入并根据这些输入向他们提供推荐列表。我正在使用链表数据结构,并且我可以获得程序的一部分来运行。但是,我目前遇到了一个似乎无法解决的错误。这是我遇到的问题:Traceback(mostrecentcalllast):File"/Use......
  • 如何实现 Grad-CAM 在 TensorFlow ResNet152V2 上查看激活图/热图以进行图像分类
    您好,我正在使用ResNet152V2做一个关于TensorFlow图像分类的小项目。我编写了一个Train-Predict.py脚本,它能够训练trained_weights.hdf5文件以成功预测自闭症和非自闭症人士的图像。此处。是脚本:#ImportLibrariesimportosimportnumpyasnp......
  • 如何忽略或绕过导致 NoneType 不可迭代对象的实例
    我正在尝试解析Edgar数据库中10K的部分,当我运行以下代码时,#pipinstalledgartoolsimportpandasaspdfromedgarimport*#TelltheSECwhoyouareset_identity("[email protected]")filings2=get_filings(form='10-K',amendments=False,......
  • 如何在.NET Framework,或NET8以前的项目中使用C# 12的新特性
    前两天发了一篇关于模式匹配的文章,链接地址,有小伙伴提到使用.NET6没法体验C#新特性的疑问,其实呢只要本地的SDK源代码编译器能支持到的情况下(直接下载VS2022或者VS的最新preview版本)只需要做很小的改动就可以支持的.目前仍然还有一些小伙伴因为历史原因可能还在写.NETFra......
  • PermissionError: [Errno 13] 权限被拒绝: 生产服务器上的“/root/.u2net”
    我正在使用rembg,它可以在我的本地计算机上运行,​​但在生产中会引发错误。所以我认为这与linux操作系统目录权限有关。这是服务器的完整日志:Traceback(mostrecentcalllast):File"/home/airnet-technologies-test-bgrm/htdocs/test-bgrm.airnet-technologies.com......
  • 使用列表理解过滤字典列表并处理 None 时,为什么会出现“NoneType 对象不可迭代”?
    在Python中,我使用列表理解来过滤带有键的字典列表。我正在处理None但仍然收到错误“NoneType对象不可迭代”。我知道这一定是一件简单的事情,但我看不到。为什么仍然出错?这是我重现问题的代码:defprocess_data(data,key):return[{k:[vforvinvali......