Populating a Collection Property of a fixture with autofixture
Asked Answered
B

3

7

I have just started using AutoFixture, and i am getting the basics down (from what i can see there is much more to it) but i am having an issue and i am not 100% sure what the best practice is for stuff like this.

I am testing a controller, and part of the process is the action can return one of two views.

  • If a category has children - show the category listing view
  • If a category does not have children show the product listing view

So i am thinking of a few tests for that behavior, but the fixture data returned would be different. One would return a count of 0, the other a greater count then zero, so i would like the fixture to help me with that.

I have been looking around, and maybe i have to create a customisation of some sort, but was hoping the basic API could help me here. I tried this:

var category = _fixture.Build<Category>()
    .Do(x => x.SubCategories = _fixture.CreateMany<Category>(3).ToList())
    .Create();

_fakeCategoryService
    .Setup(x => x.GetById(id))
    .Returns(category);

This compiles and tests run (and fail), but the sub categories always has a count of 0, so i am thinking my call to Create Many in the do is all wrong (it kinda looks wrong but i am still unsure what it should be replaced with).

UPDATE: should read the cheat sheet a bit better!

var category = _fixture.Build<Category>()
    .With(x => x.SubCategories, _fixture.CreateMany<Category>(3).ToList())
    .Create();

This works, if there is a better way please let me know.

Bowler answered 10/4, 2014 at 16:0 Comment(0)
V
10

Yes, Build is correct.


If you want to customize the creation algorithm for a single Category use Build:

var actual = fixture
    .Build<Category>()
    .With(x => x.SubCategories, 
        fixture.CreateMany<Category>().ToList())
    .Create();

Assert.NotEmpty(actual.SubCategories);

If you want to customize the creation algorithm for all Category instances use Customize:

fixture.Customize<Category>(c => c
    .With(x => x.SubCategories,
        fixture.CreateMany<Category>().ToList()));

var actual = fixture.Create<Category>();

Assert.NotEmpty(actual.SubCategories);
Valarievalda answered 10/4, 2014 at 17:43 Comment(0)
M
7

was hoping the basic API could help me here

It does help you, if you know how to listen :) AutoFixture was originally build as a tool for Test-Driven Development (TDD), and TDD is all about feedback. In the spirit of GOOS, you should listen to your tests. In this case it's saying the same as the Framework Design Guidelines:

DO NOT provide settable collection properties.

Instead of assigning a list wholesale to a property, consider

  • making the collection property read-only, and let clients invoke Add, etc.
  • taking the collection as a constructor parameter instead of mutating property

In the latter case, AutoFixture will automatically provide a populated collection when it invokes the constructor, although in this particular case, since you have a potentially recursive graph, you may need to explicitly handle it.

In the first case, AutoFixture doesn't do anything out of the box, but has an AddManyTo extension method, enabling you to fill a collection in a single statement:

fixture.AddManyTo(category.SubCategories);
Miocene answered 10/4, 2014 at 18:3 Comment(3)
I meant it as i was getting it wrong not the API was wrong :) Thanks for the additional info, i will take a look into it. I think i saw an example of the AddManyTo function on your blog!Bowler
Hi Mark, this app is not the biggest so the Category class is the classed used for EF so i don't believe (will have to check again) that you can work it without it being a settable property. For a pure domain object i get you.Bowler
It's been a long time since I used EF, but I believe you're correct :/Miocene
W
1

You can do this stub with a custom list:

var stub = _fixture.Build<Entity>().With(x=> x.field, config).CreateMany().ToList();

Documentation.

Warmongering answered 17/9, 2019 at 14:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.