Sebastian N
Sebastian N

Reputation: 31

XUnit with NSubstitute - Substituted public IReadOnlyCollection empty besides private list has a value

I have an entity aggregate (WeeklyMenuItem) containing a sub-entity (WeeklyMenuItemIngredient) as a collection. The WeeklyMenuItemIngredient can only be set via methods (AddOrUpdateIngredient, RemoveIngredient). The public collection is a IReadOnlyCollection with a private readonly List.

I want to create a test for "adding ingredients" using NSubstitute. The AddOrUpdateIngredient method of the substitute adds the ingredient to the private list, but later I cannot access the value through the public ReadOnlyCollection.

If I create the WeeklyMenuItem as a normal class, I can access the value. Only the substitute has the problem.

Does NSubstitute not support IReadOnlyCollections?

The WeeklyMenuItem with ReadOnlyCollection and AddOrUpdateIngredient method:

public partial class WeeklyMenuItem(long dayId,
                                    long? createdById = null,
                                    long? createdId = null,
                                    long? updatedById = null,
                                    long? updatedId = null) : BaseEntity<long>, IAggregateRoot

private readonly List<WeeklyMenuItemIngredient> _weeklyMenuItemIngredient = [];
public virtual IReadOnlyCollection<WeeklyMenuItemIngredient> WeeklyMenuItemIngredient => _weeklyMenuItemIngredient.AsReadOnly();

public void AddOrUpdateIngredient(long ingredientId, decimal amount)
{
    if (!WeeklyMenuItemIngredient.Any(e => e.WeeklyMenuItemId == this.Id && e.IngredientId == ingredientId))
    {
        _weeklyMenuItemIngredient.Add(new WeeklyMenuItemIngredient(this.Id, ingredientId, amount));
        return;
    }

    var dishIngredient = WeeklyMenuItemIngredient.First(e => e.WeeklyMenuItemId == this.Id && e.IngredientId == ingredientId);
    dishIngredient.SetAmount(amount);
}

The XUnit test with the substitute creation methods:

private readonly decimal amount1 = 1;
private readonly decimal amount2 = 2;

[Fact]
public void AddIngredient()
{
    var weeklyMenuItem1 = new WeeklyMenuItem(1, null, null, null, null); //working 
    var weeklyMenuItem1 = WeeklyMenuItemTestData.GetWeeklyMenuItem1(DayTestData.GetDay1(WeekTestData.GetWeek1())); //not working
    var ingredient1 = IngredientTestData.GetIngredient1();

    weeklyMenuItem1.AddOrUpdateIngredient(ingredient1.Id, amount1);

    var addedIngredient1 = weeklyMenuItem1.WeeklyMenuItemIngredient.FirstOrDefault(); //Empty - result is null value

    weeklyMenuItem1.WeeklyMenuItemIngredient.Should().HaveCount(1);
    addedIngredient1.Should().NotBeNull();
    addedIngredient1!.IngredientId.Should().Be(ingredient1.Id);
    addedIngredient1!.Amount.Should().Be(amount1);
}

public static WeeklyMenuItem GetWeeklyMenuItem1(Day? day)
{
    var weeklyMenuItem1 = Substitute.For<WeeklyMenuItem>(day?.Id, null, null, null, null);
    weeklyMenuItem1.Id.Returns(Id1);
    weeklyMenuItem1.Day.Returns(day);
    return weeklyMenuItem1;
}

public static Day GetDay1(Week? week)
{
    var day1 = Substitute.For<Day>(Date1, week?.Id, BusinessesIsOpen);
    day1.Id.Returns(Id1);
    day1.Week.Returns(week);
    return day1;
}

public static Week GetWeek1()
{
    var week1 = Substitute.For<Week>(Year1, Value1);
    week1.Id.Returns(Id1);
    return week1;
}

Upvotes: 0

Views: 19

Answers (0)

Related Questions