AutoFixture 是否有一种机制来检查返回任何类型的列表的方法是否永远不会返回 null

本文关键字:返回 是否 任何 列表 类型 永远 null 方法 检查 机制 一种 | 更新日期: 2023-09-27 18:36:54

我想编写一个测试来检查给定命名空间中的类。如果返回 null,则必须检查返回任何类型的列表的类的所有方法。如果是这样,测试必须失败。

类/方法本身也有依赖项(构造函数参数和方法参数),应该自动模拟。

AutoFixture 是否有一种机制来检查返回任何类型的列表的方法是否永远不会返回 null?

示例类:

public class UserService
{
    private readonly IRemotingFacade _remotingFacade;
    public UserService(IRemotingFacade remotingFacade)
    {
        _remotingFacade = remotingFacade;
    }
    // directly return a list
    public IEnumerable<User> GetUsers()
    {
    }
    // directly return a list, pass method parameters
    public IEnumerable<User> GetUsers(string filter)
    {
    }
    // wrapped list
    public IBusinessResponse<IEnumerable<User>> GetUsers()
    {
    }

    // wrapped list, pass method parameters
    public IBusinessResponse<IEnumerable<User>> GetUsers(string filter)
    {
    }
}

因此,请确认列表可以包装在另一个对象中。

AutoFixture 是否有一种机制来检查返回任何类型的列表的方法是否永远不会返回 null

AutoFixture 3.18.0引入了一个名为Idioms.FsCheck的新胶水库,它使用FsCheck来实现可重用的 名为 ReturnValueMustNotBeNullAssertion 的断言。

这个新的断言验证(或至少使可能)返回值(查询)的方法不返回 null。

安装

Idioms.FsCheck 在 NuGet 上可用:

PM> Install-Package AutoFixture.Idioms.FsCheck

场景

UserService使用注入的IRemotingFacade实例并公开两个[1]查询:

  • 用户[] 获取用户()
  • User[] GetUsers(int)

场景 #1:注入的IRemotingFacade实例返回 null:

[Theory, UnitTestConventions]
public void Scenario1(
    ISpecimenBuilder builder,
    [Frozen]Mock<IRemotingFacade> stub)
{
    stub.Setup(x => x.GetUsers()).Returns((User[])null);
    var sut = from x in new Methods<UserService>() select x.GetUsers();
    var assertion = new ReturnValueMustNotBeNullAssertion(builder);
    Assert.Throws<ReturnValueMustNotBeNullException>(() =>
        assertion.Verify(sut));
}

场景 #2:注入的IRemotingFacade实例不返回 null:

[Theory, UnitTestConventions]
public void Scenario2(
    ISpecimenBuilder builder,
    [Frozen]Mock<IRemotingFacade> stub,
    User[] users)
{
    stub.Setup(x => x.GetUsers()).Returns(users);
    var sut = from x in new Methods<UserService>() select x.GetUsers();
    var assertion = new ReturnValueMustNotBeNullAssertion(builder);
    Assert.DoesNotThrow(() => assertion.Verify(sut));
}

场景 3:如果i-1,则返回 null GetUsers(int)

[Theory, UnitTestConventions]
public void Scenario3(
    ISpecimenBuilder builder,
    [Frozen]Mock<IRemotingFacade> stub,
    User[] users)
{
    stub.Setup(x => x.GetUsers()).Returns(users);
    var sut = from x in new Methods<UserService>() 
              select x.GetUsers(default(int));
    var assertion = new ReturnValueMustNotBeNullAssertion(builder);
    Assert.Throws<ReturnValueMustNotBeNullException>(
        () => assertion.Verify(sut));
}

言论

如果只安装了 F# 3.1,还可以在 app.config 文件中添加程序集绑定重定向:

<dependentAssembly>
  <assemblyIdentity name="FSharp.Core" 
                    publicKeyToken="b03f5f7f11d50a3a" 
                    culture="neutral" />
  <bindingRedirect oldVersion="0.0.0.0-4.3.1.0" 
                   newVersion="4.3.1.0" />
</dependentAssembly>

UnitTestConventionsAttribute定义为:

internal class UnitTestConventionsAttribute : AutoDataAttribute
{
    internal UnitTestConventionsAttribute()
        : base(new Fixture().Customize(new AutoMoqCustomization()))
    {
    }
}

反射查询使用反照率执行。


[1] 对于演示,我简化了原始代码,如下所示:

public class User
{
}
public interface IRemotingFacade
{
    User[] GetUsers();
}
public class UserService
{
    private readonly IRemotingFacade remotingFacade;
    public UserService(IRemotingFacade remotingFacade)
    {
        if (remotingFacade == null)
            throw new ArgumentNullException("remotingFacade");
        this.remotingFacade = remotingFacade;
    }
    public User[] GetUsers()
    {
        return this.remotingFacade.GetUsers();
    }
    public User[] GetUsers(int i)
    {
        if (i == -1)
            return null;
        return this.remotingFacade.GetUsers();
    }
}

Ruben Bartelink上面的评论是正确的。令人惊讶的是,AutoFixture.Idioms(还没有)有这个特定的测试,尽管引入该库的第一个惯用测试在命令端是等效的:GuardClauseAssertion

但是,我认为这是一个好主意(我不知道为什么我以前没有想到这一点),所以我现在在积压工作中添加了一个新任务。