【问题标题】:Autofixture test for invalid constructor parameter无效构造函数参数的自动夹具测试
【发布时间】:2013-02-11 06:30:48
【问题描述】:

我有以下课程和测试。我想测试将空值作为参数传递给构造函数,并期待ArgumentNullException。但由于我使用 Autofixture 的 CreateAnonymous 方法,我得到了 TargetInvocationException

编写这些测试的正确方法是什么?

public sealed class CreateObject : Command {
    // Properties
    public ObjectId[] Ids { get; private set; }
    public ObjectTypeId ObjectType { get; private set; }
    public UserId CreatedBy { get; private set; }

    // Constructor
    public CreateObject(ObjectId[] ids, ObjectTypeId objectType, UserId createdBy) {
      Guard.NotNull(ids, "ids");
      Guard.NotNull(objectType, "objectType");
      Guard.NotNull(createdBy, "createdBy");

      Ids = ids;
      ObjectType = objectType;
      CreatedBy = createdBy;
    }
}

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void constructor_with_null_ids_throw() {
    fixture.Register<ObjectId[]>(() => null);
    fixture.CreateAnonymous<CreateObject>();
}

【问题讨论】:

  • 我会在更高级别进行此类 Guard 子句验证 - 请参阅 stackoverflow.com/a/11455580/11635。另外,@ 987654322@(是的,我知道这些都没有遇到您关于@ 987654329@的问题,这就是为什么这不是答案,但第一步是澄清代码以便您可以使用它 - 即使这是一个错误,您将需要生成更清晰的重现和临时解决方法

标签: autofixture


【解决方案1】:

IMO,Ruben Bartelink's comment 是最佳答案。

使用AutoFixture.Idioms,您可以改为:

var fixture = new Fixture();
var assertion = new GuardClauseAssertion(fixture);
assertion.Verify(typeof(CreateObject).GetConstructors());

如果任何构造函数中的任何构造函数参数缺少保护子句,Verify 方法将为您提供非常详细的异常消息。


FWIW,AutoFixture 广泛使用反射,所以我不认为它会引发 TargetInvocationException 的错误。虽然它可以解开所有TargetInvocationException 实例并重新抛出它们的InnerException 属性,但这也意味着处理(可能)有价值的信息(例如AutoFixture 堆栈跟踪)。我已经考虑过这一点,但出于这个原因,我不想将 AutoFixture 朝那个方向发展。客户端总是可以过滤掉信息,但如果信息被过早地删除,客户端就无法取回它。

如果您更喜欢另一种方法,编写一个解开异常的辅助方法并不难 - 可能是这样的:

public Exception Unwrap(this Exception e)
{
    var tie = e as TargetInvocationException;
    if (tie != null)
        return tie.InnerException;
    return e;
}

【讨论】:

  • 检查 ParamName 值怎么样?如果我在没有指定 ParamName 或错误值的情况下抛出新的 ArgumentNullException,那么您的测试将继续通过。
  • 如果你这样做了,静态代码分析工具会发现并警告你。 IIRC,Visual Studio 代码分析就是这样做的。
  • 但从 TDD 的角度来看,这不是完美的解决方案 :) 当然,我使用静态分析工具(R# 警告错误值),但我想在单元测试中检查 ParamName。 AutoFixture 可以吗?
  • IIRC GuardClauseAssertion 不这样做。尽管如此,没有理由仅仅因为你在做 TDD 就放弃像代码分析这样非常好的工具:blog.ploeh.dk/2011/04/29/Feedbackmechanismsandtradeoffs
  • @MarkSeemann 哦,好吧,我就是这么做的,谢谢您的快速回复。我只想说 AutoFixture 对于编写我的测试有多么重要。一言以蔽之,太棒了
【解决方案2】:

我在寻找类似的东西时遇到了这个问题。我想补充一点,结合 automoqcustomization 和 xunit,下面的代码也可以工作,而且更简洁。

    [Theory, AutoMoqData]
    public void Constructor_GuardClausesArePresent(GuardClauseAssertion assertion)
    {
        assertion.Verify(typeof(foo).GetConstructors());
    }

您只需要按如下方式创建 AutoMoqData 属性。

    public class AutoMoqDataAttribute : AutoDataAttribute
    {
        public AutoMoqDataAttribute() : base(() => new Fixture().Customize(new AutoMoqCustomization()))
        {

        }
    }

【讨论】:

    猜你喜欢
    • 2016-11-07
    • 2023-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-20
    • 2019-11-07
    • 1970-01-01
    • 2018-03-01
    相关资源
    最近更新 更多