unit-testing - 如何为特定类自定义 AutoFixture 行为

标签 unit-testing autofixture

我需要启用 AutoFixture 来创建具有循环引用的类型实例(来自第三方提供的 API)。为此,我可以删除默认的 ThrowingRecursionBehavior如下所示:

public class RecursiveObjectCustomization : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
            .ToList()
            .ForEach(b => fixture.Behaviors.Remove(b));
        fixture.Behaviors.Add(new OmitOnRecursionBehavior());
    }
 }

但是,我知道这将删除 ThrowingRecursionBehavior通过属性应用自定义时的所有类型。如何将修改后的行为限制为仅适用于特定类型?

最佳答案

您必须为此创建自定义行为。

这里有一些事情要开始:

public class OmitOnRecursionForRequestBehavior : ISpecimenBuilderTransformation
{
    private const int DefaultRecursionDepth = 1;
    private readonly int recursionDepth;
    private readonly object request;

    public OmitOnRecursionForRequestBehavior(object request)
        : this(request, DefaultRecursionDepth)
    {
    }

    public OmitOnRecursionForRequestBehavior(
        object request,
        int recursionDepth)
    {
        if (request == null)
            throw new ArgumentNullException("request");
        if (recursionDepth < 1)
            throw new ArgumentOutOfRangeException(
                "recursionDepth",
                "Recursion depth must be greater than 0.");

        this.recursionDepth = recursionDepth;
        this.request = request;
    }

    public ISpecimenBuilder Transform(ISpecimenBuilder builder)
    {
        if (builder == null)
            throw new ArgumentNullException("builder");

        return new RecursionGuard(
            builder,
            new RecursionForRequestHandler(
                request,
                new OmitOnRecursionHandler(),
                builder),
            recursionDepth);
    }
}

public class RecursionForRequestHandler : IRecursionHandler
{
    private readonly object request;
    private readonly IRecursionHandler handlerForRequest;
    private readonly ISpecimenBuilder handler;

    public RecursionForRequestHandler(
        object request,
        IRecursionHandler handlerForRequest,
        ISpecimenBuilder handler)
    {
        if (request == null)
            throw new ArgumentNullException("request");
        if (handlerForRequest == null)
            throw new ArgumentNullException("handlerForRequest");
        if (handler == null)
            throw new ArgumentNullException("handler");

        this.request = request;
        this.handlerForRequest = handlerForRequest;
        this.handler = handler;
    }

    public object HandleRecursiveRequest(
        object request,
        IEnumerable<object> recordedRequests)
    {
        if (this.request.Equals(request))
            return handlerForRequest.HandleRecursiveRequest(
                request,
                recordedRequests);

        return handler.Create(request, new SpecimenContext(handler));
    }
}

这是你将如何使用它:
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(MyType)));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(AnotherType)));

请注意,您不会删除 ThrowingRecursionBehavior因为它将用于保护其他请求,否则为 StackOverflowException将被抛出。

但是,如果您指定 recursionDepth大于 1,您必须删除 ThrowingRecursionBehavior并创建一个大于或等于 recursionDepth 的自定义.
public class DepthThrowingRecursionBehavior : ISpecimenBuilderTransformation
{
    private readonly int recursionDepth;

    public DepthThrowingRecursionBehavior(int recursionDepth)
    {
        if (recursionDepth < 1)
            throw new ArgumentOutOfRangeException(
                "recursionDepth",
                "Recursion depth must be greater than 0.");

        this.recursionDepth = recursionDepth;
    }

    public ISpecimenBuilder Transform(ISpecimenBuilder builder)
    {
        if (builder == null)
            throw new ArgumentNullException("builder");

        return new RecursionGuard(
            builder,
            new ThrowingRecursionHandler(),
            recursionDepth);
    }
}
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
    .ToList()
    .ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthThrowingRecursionBehavior(2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(MyType), 2));
fixture.Behaviors.Add(new OmitOnRecursionForRequestBehavior(typeof(AnotherType), 1));

关于unit-testing - 如何为特定类自定义 AutoFixture 行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31855842/

相关文章:

c# - 在调用方法中模拟局部变量

c# - 使用 autofixture 创建结构不会引发公共(public)构造函数错误

c# - 带有 Entity Framework 的 AutoFixture - 将 int 映射到枚举

unit-testing - XUnit 和 AutoFixture Exception No Data found for (test name)

c# - Autofixture,创建一个字典列表<string, object> 交替键

c# - AutoFixture - 配置夹具以限制字符串生成长度

unit-testing - Resharper "Run All Tests"已损坏

c# - 如何在 EF4 中回滚单元测试拆解?

java - 为什么我们应该通过mock来了解邻居对象的信息?

ios - 如何为 UIViewControllers 编写单元测试用例?