Moq a virtual ICollection<> property that has a private set : "Invalid setup on a non-virtual"

StackOverflow https://stackoverflow.com/questions/16988042

  •  31-05-2022
  •  | 
  •  

Question

I'm running into a problem where I try to mock an object which contain a property Items of type ICollection<>. I get the following error :

System.NotSupportedException : Invalid setup on a non-virtual (overridable in VB) member: m => m.Items

The problem is that the property Items is already virtual.

I reproduced the error that I get in my project, in the Sandbox below :

public class ItemList
{
    public virtual int Id { get; set; }
}

public class SpecialList
{
    public virtual string Token { get; internal set; }
    public virtual ICollection<ItemList> Items { get; private set; }
}

That error occurs in my Test when I try to SetupProperty like that :

[TestFixture]
public class TestSpecialList
{
    [Test]
    public void Mocking_Virtual_ICollection()
    {
        var mockModel = new Mock<SpecialList>();
        var listItem = new List<ItemList> {new ItemList {Id = 007}};

        mockModel.SetupProperty(m => m.Items, listItem);
    }
}

Am I doing something wrong? Is it possible to Moq an object containing a ICollection<> property?

Was it helpful?

Solution

Try using either of these:

mockModel.Setup(m => m.Items).Returns(listItem);
mockModel.SetupGet(m => m.Items).Returns(listItem);

The method SetupProperty is used when you want to track its value, see moq wiki. Although I am not enterily sure why SetupProperty fails, as its intention is to be able to assing and retrieve the property value, it seems likely to be caused by the private get.

To be clear, let's assume your property has a public set. In that case when using Setup or SetupGet, doing something like mockModel.Object.Items = new List<ItemList>(); would have no effect and you would still see the list with a single item. However with SetupProperty the same statement would have changed the value returned by the property.

Basically SetupProperty allows to get AND SET the value of a property and that's why I think it cannot be used with a private set.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top