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

 更新时间:2024年07月21日 09:20:27   作者:万雅虎  
AutoFixture是一个.NET库,旨在简化单元测试中的数据设置过程,通过自动生成测试数据,它帮助开发者减少测试代码的编写量,使得单元测试更加简洁、易读和易维护,本文介绍.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

到此这篇关于.NET单元测试使用AutoFixture按需填充的几种方式和最佳实践记录的文章就介绍到这了,更多相关.NET单元测试使用AutoFixture按需填充内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • asp.net Server.MapPath方法注意事项

    asp.net Server.MapPath方法注意事项

    当我发布之后,对存储图片的文件夹创建了虚拟目录,并赋予该目录写入的权限,但是,当我上传图片的时候,总是失败。以前没遇到过这种情况,觉得很是怪异,所以想尽办法去解决。
    2008-09-09
  • .Net Core和jexus配置HTTPS服务方法

    .Net Core和jexus配置HTTPS服务方法

    下面小编就为大家分享一篇.Net Core和jexus配置HTTPS服务方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-02-02
  • 使用微信PC端的截图dll库实现微信截图功能

    使用微信PC端的截图dll库实现微信截图功能

    这篇文章主要为大家详细介绍了使用微信PC端的截图dll库实现微信截图功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06
  • asp.net core为IHttpClientFactory添加动态命名配置

    asp.net core为IHttpClientFactory添加动态命名配置

    某些时候我们需要为HttpClient动态配置一些东西, 例如证书等, 例如服务是一个回调服务, 而被回调方采用了自定义的https(即自定义证书),本文就将讲述如何实现这种需求
    2021-06-06
  • WPF数据驱动修改绑定

    WPF数据驱动修改绑定

    这篇文章介绍了WPF数据驱动修改绑定的方法,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-04-04
  • ASP.NET Core实现中间件的几种方式

    ASP.NET Core实现中间件的几种方式

    这篇文章介绍了ASP.NET Core实现中间件的几种方式,文中通过示例代码介绍的非常详细。对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • .Net页面局部更新引发的思考

    .Net页面局部更新引发的思考

    这篇文章主要是由.Net页面局部更新引发的一系列思考,整理了实现局部更新的解决方案及改进方案,感兴趣的小伙伴们可以参考一下
    2016-06-06
  • asp.net+sqlserver实现的简单高效的权限设计示例

    asp.net+sqlserver实现的简单高效的权限设计示例

    大部分系统都有权限系统。一般来说,它能管控人员对某个否页面的访问;对某些字段、控件可见或者不可见。对gridview中的数据是否可删除、可添加、可新增等等。
    2010-04-04
  • asp.net网站底部的版权信息实现代码且可维护

    asp.net网站底部的版权信息实现代码且可维护

    网站底部的版权信息在特殊情况还是比较重要的所以在实现的时候一定要尽可能的做到可维护性,接下来将介绍一些技巧可达到可维护效果,感兴趣的你可不要错过了哈
    2013-02-02
  • Visual Studio 2017中找回消失的“在浏览器中查看”命令

    Visual Studio 2017中找回消失的“在浏览器中查看”命令

    这篇文章主要为大家详细介绍了如何在Visual Studio 2017中找回消失的“在浏览器中查看”命令,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03

最新评论