Autofixture generates a custom list

Here is my goal:

public class Symbol { private readonly string _identifier; private readonly IList<Quote> _historicalQuotes; public Symbol(string identifier, IEnumerable<Quote> historicalQuotes = null) { _identifier = identifier; _historicalQuotes = historicalQuotes; } } public class Quote { private readonly DateTime _tradingDate; private readonly decimal _open; private readonly decimal _high; private readonly decimal _low; private readonly decimal _close; private readonly decimal _closeAdjusted; private readonly long _volume; public Quote( DateTime tradingDate, decimal open, decimal high, decimal low, decimal close, decimal closeAdjusted, long volume) { _tradingDate = tradingDate; _open = open; _high = high; _low = low; _close = close; _closeAdjusted = closeAdjusted; _volume = volume; } } 

I need a Symbol instance populated with a Quote list.

In my test, I want to check that I can return all quotes whose closing price is above a certain value or higher. Here is my test:

 [Fact] public void PriceUnder50() { var msftIdentifier = "MSFT"; var quotes = new List<Quote> { new Quote(DateTime.Parse("01-01-2009"), 0, 0, 0, 49, 0, 0), new Quote(DateTime.Parse("01-02-2009"), 0, 0, 0, 51, 0, 0), new Quote(DateTime.Parse("01-03-2009"), 0, 0, 0, 50, 0, 0), new Quote(DateTime.Parse("01-04-2009"), 0, 0, 0, 10, 0, 0) }; _symbol = new Symbol(msftIdentifier, quotes); var indicator = new UnderPriceIndicator(50); var actual = indicator.Apply(_symbol); Assert.Equal(2, actual.Count); Assert.True(actual.Any(a => a.Date == DateTime.Parse("01-01-2009"))); Assert.True(actual.Any(a => a.Date == DateTime.Parse("01-04-2009"))); Assert.True(actual.Any(a => a.Price == 49)); Assert.True(actual.Any(a => a.Price == 10)); } 

OK

Now I want to do this using Autofixture, im a real beginner. I read almost everything I could on the Internet about this tool (authorโ€™s blog, frequently asked questions about codeple, github source code). I understand the main features of car chemistry, but now I want to use autofixture in my real project. Here is what I have tried so far.

 var msftIdentifier = "MSFT"; var quotes = new List<Quote>(); var random = new Random(); fixture.AddManyTo( quotes, () => fixture.Build<Quote>().With(a => a.Close, random.Next(1,49)).Create()); quotes.Add(fixture.Build<Quote>().With(a => a.Close, 49).Create()); _symbol = new Symbol(msftIdentifier, quotes); // I would just assert than 49 is in the list Assert.True(_symbol.HistoricalQuotes.Contains(new Quote... blabla 49)); 

Ideally, I would prefer to directly create a Symbol binding, but I do not know how to set up my list of quotes. And I'm not sure that my test is general, because in another test I will need to check that the specific value is higher and not lower, so I'm going to duplicate the โ€œdevice codeโ€ and manually add the quote = 51.

So my questions are:

1 - How can I use the car receiver?

2 - Is it possible to improve the way I use auto-set-top boxes in my example?

+5
refactoring autofixture
source share
1 answer

AutoFixture was originally created as a test development tool (TDD), and TDD is feedback . In the spirit of GOOS, you should listen to your tests . If tests are hard to write, you should consider your API design. AutoFixture tends to reinforce that kind of feedback , and that's what it tells me.

Make comparison easier

Firstly, not related to AutoFixture, the Quote class simply accesses the correct value object , so I override Equals to make it easier to compare expected and actual instances:

 public override bool Equals(object obj) { var other = obj as Quote; if (other == null) return base.Equals(obj); return _tradingDate == other._tradingDate && _open == other._open && _high == other._high && _low == other._low && _close == other._close && _closeAdjusted == other._closeAdjusted && _volume == other._volume; } 

(Remember to also override GetHashCode .)

Copy and update

The above test attempt seems to imply that we lack the ability to change one field while maintaining a constant constant . Taking a cue from functional languages, we can introduce a way to do this in the Quote class itself:

 public Quote WithClose(decimal newClose) { return new Quote( _tradingDate, _open, _high, _low, newClose, _closeAdjusted, _volume); } 

This type of API is generally very useful for Value objects, to the extent that I always add such methods to my Value objects.

Do the same with Symbol :

 public Symbol WithHistoricalQuotes(IEnumerable<Quote> newHistoricalQuotes) { return new Symbol(_identifier, newHistoricalQuotes); } 

This makes it easy to ask AutoFixture anything you donโ€™t like, while at the same time explicitly specifying only what you need.

Testing with AutoFixture

The original test can now be rewritten as:

 [Fact] public void PriceUnder50() { var fixture = new Fixture(); var quotes = new[] { fixture.Create<Quote>().WithClose(49), fixture.Create<Quote>().WithClose(51), fixture.Create<Quote>().WithClose(50), fixture.Create<Quote>().WithClose(10), }; var symbol = fixture.Create<Symbol>().WithHistoricalQuotes(quotes); var indicator = fixture.Create<UnderPriceIndicator>().WithLimit(50); var actual = indicator.Apply(symbol); var expected = new[] { quotes[0], quotes[3] }; Assert.Equal(expected, actual); } 

Only parts of the test case that you care about are indicated in this test, while AutoFixture takes care of all other values โ€‹โ€‹that do not affect the test case. This makes the test more reliable as well as more readable.

+10
source share

All Articles