Ответ 1
Создание A с пустым списком Bs
Легко создать экземпляр A с пустым списком Bs:
var fixture = new Fixture();
fixture.Inject(Enumerable.Empty<B>());
var a = fixture.Create<A>();
Создание небольшого дерева
Намного сложнее создать небольшое дерево, но это возможно. Вы уже на своем пути, думая о RecursionGuard
. Чтобы проверить, может ли это работать, я скопировал большую часть кода из RecursionGuard
и создал это DepthRecursionGuard
как доказательство концепции:
public class DepthRecursionGuard : ISpecimenBuilderNode
{
private readonly ISpecimenBuilder builder;
private readonly Stack<object> monitoredRequests;
public DepthRecursionGuard(ISpecimenBuilder builder)
{
if (builder == null)
{
throw new ArgumentNullException("builder");
}
this.monitoredRequests = new Stack<object>();
this.builder = builder;
}
public object Create(object request, ISpecimenContext context)
{
if (this.monitoredRequests.Count(request.Equals) > 1)
return this.HandleRecursiveRequest(request);
this.monitoredRequests.Push(request);
var specimen = this.builder.Create(request, context);
this.monitoredRequests.Pop();
return specimen;
}
private object HandleRecursiveRequest(object request)
{
if (typeof(IEnumerable<B>).Equals(request))
return Enumerable.Empty<B>();
throw new InvalidOperationException("boo hiss!");
}
public ISpecimenBuilderNode Compose(IEnumerable<ISpecimenBuilder> builders)
{
var builder = ComposeIfMultiple(builders);
return new DepthRecursionGuard(builder);
}
public virtual IEnumerator<ISpecimenBuilder> GetEnumerator()
{
yield return this.builder;
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
private static ISpecimenBuilder ComposeIfMultiple(
IEnumerable<ISpecimenBuilder> builders)
{
var isSingle = builders.Take(2).Count() == 1;
if (isSingle)
return builders.Single();
return new CompositeSpecimenBuilder(builders);
}
}
Обратите внимание на измененную реализацию метода Create
, а также на конкретную обработку IEnumerable<B>
в HandleRecursiveRequest
.
Чтобы сделать это пригодным для использования с экземпляром Fixture
, я также добавил это DepthRecursionBehavior
:
public class DepthRecursionBehavior : ISpecimenBuilderTransformation
{
public ISpecimenBuilder Transform(ISpecimenBuilder builder)
{
return new DepthRecursionGuard(builder);
}
}
Это позволило мне создать небольшое дерево:
var fixture = new Fixture();
fixture.Behaviors.OfType<ThrowingRecursionBehavior>()
.ToList().ForEach(b => fixture.Behaviors.Remove(b));
fixture.Behaviors.Add(new DepthRecursionBehavior());
var a = fixture.Create<A>();
Хотя это возможно, это, на мой взгляд, слишком сложно, поэтому я создал рабочий элемент, чтобы упростить его в будущее.
Обновление 2013.11.13: из AutoFixture 3.13.0 глубину рекурсии можно настроить с помощью этого API.