Próbuję przezwyciężyć scenariusz, w którym klasa ma parametr konstruktora ciągów znaków, który nie może być spełniony przez żaden stary ciąg wygenerowany przez Autofixture (wartość wyglądająca Guid-y).Jak używać funkcji Autofixture (v3) z programem ICustomization, ISpecimenBuilder, aby poradzić sobie z parametrem konstruktora?
Zanim będziesz miał ochotę odpowiedzieć po prostu za pomocą linku do Mark Seemann's Ploeh blog entry on Convention-based Customizations, powiem, że odnoszę się do niego i innych wpisów na blogu jego do tego testu, którego nie mogę przejść.
Kiedy przechodzę do debugowania, widzę, że w pewnym momencie parametr konstruktora jest przekazywany z poprawną wartością, ale test nadal kończy się niepowodzeniem z wartością koloru Guid-y. Myślę, że ma to coś wspólnego z tym, że istnieje zarówno wartość parametru "kolor", i właściwość "Kolor", która ma być wypełniona przez Autofixture. Czy napisałem ISpecimenBuilder, który adresuje parametr konstruktora, ale testuję wartość właściwości publicznej (dwie różne rzeczy)?
Wiem, że to wszystko jest przesadą dla przykładu, ale wyobrażam sobie bardziej skomplikowany scenariusz, w którym użycie metody Build<T>().With()
nie byłoby SUCHĄ.
niewydolnego test
[Fact]
public void Leaf_Color_Is_Brown()
{
// arrange
var fixture = new Fixture().Customize(new LeafColorCustomization());
// act
var leaf = fixture.Create<Leaf>();
// using .Build<>.With(), test passes
//var leaf = fixture.Build<Leaf>().With(l => l.Color, "brown").CreateAnonymous();
// assert
Assert.True(leaf.Color == "brown");
}
SUT
public class Leaf
{
public Leaf(string color)
{
if (color != "brown")
throw new ArgumentException(@"NO LEAF FOR YOU!");
this.Color = color;
}
public string Color { get; set; }
}
Realizacja CompositeCustomization (znam AutoMoqCustomization() nie jest potrzebne w tym przykładzie)
public class LeafCustomization : CompositeCustomization
{
public LeafCustomization()
: base(
new LeafColorCustomization(),
new AutoMoqCustomization()) { }
}
Liść specyficzne ICustomization
public class LeafColorCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
if (fixture == null)
throw new ArgumentNullException("fixture");
fixture.Customizations.Add(new LeafBuilder());
}
}
String-konstruktor-z-imienia-of-Color specyficzne ISpecimenBuilder
public class LeafBuilder : ISpecimenBuilder
{
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen(request);
if (pi.ParameterType != typeof(string) || pi.Name != "color")
return new NoSpecimen(request);
return "brown";
}
}
genialny - to działa! Re: Rozwiązanie nr 1, czy można/należy go pominąć właściwość zapisu 'Color' wewnątrz' ISpecimenBuilder' ('LeafBuilder') zamiast wewnątrz' ICustomization' ('LeafColorCustomization')? Mam wrażenie, że wiele z tych ".Without()" zaszkodziłoby implementacji, i że byłoby czystsze (szczególnie w bardziej złożonym przykładzie), aby mieć tylko serię 'fixture.Customizations.Add (new XXXBuilder ()); 'wewnątrz' ICustomization' - czy nie rozumiem, gdzie znajdują się różne dostosowania? – Jeff
@Lumirris Z pewnością poradziłbyś sobie z problemem z 'LeafBuilder'. Po prostu zajmiemy się również przypadkiem, w którym 'request' jest' PropertyInfo' oprócz przypadku, który już obsłużyłeś, gdzie jest 'ParameterInfo'. –
@MarkSeemann - [YAGNI] (http://en.wikipedia.org/wiki/You_aren't_gonna_need_it) bez względu na to, czy lepiej radzić sobie z implementacją 'ISpecimenBuilder'' LeafBuilder' przy rozważaniu bardziej złożonych scenariuszy, używając Implementacja "ICustomization" do dodania wszystkich niezbędnych implementacji 'ISpecimenBuilder'? – Jeff