简体   繁体   中英

Using Moq to mock an interface that extends IList

I am attempting to mock an interface that extends IList and get the mock to work as an IEnumerable. I was expecting the mocked object to contain an enumerable list of users, instead the enumeration yields no results. The code below works if I change the interface ITestEnumerable extends to IEnumerable instead of IList.

public interface ITestEnumerable : IList<User>
{

}

[Fact]
public void TestTest()
{
    //Arrange
    var fakes = new List<User>()
    {
        new User() { DisplayName = "Joe Smith", Mail = "jsmith@test.com" },
        new User() { DisplayName = "Jane Doe", Mail = "jdoe@test.com" }
    };
    var mockTest = new Mock<ITestEnumerable>();
    mockTest.Setup(t => t.Count).Returns(() => fakes.Count());
    mockTest.Setup(t => t[It.IsAny<int>()]).Returns<int>(i => fakes.ElementAt(i));
    mockTest.As<IEnumerable<User>>().Setup(t => t.GetEnumerator()).Returns(() => fakes.GetEnumerator());
    var testList = new List<User>();

    //Act
    testList.AddRange(mockTest.Object);

    //Assert
    Assert.NotNull(testList[0]);
}

The problem here is in the internals of AddRange function: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,79de3e39e69a4811

You can see, that first attempt is to cast it to ICollection and then there is a whole CopyTo flow.

So the easiest would be to replace it with something like this. You do mock enumerator anyway. It can also be shortened with LINQ.

foreach(var item in mockTest.Object)
{
    testList.Add(item);
}

If you want to do this with MOQ, something like this should fit:

mockTest.As<ICollection<User>>().Setup(t => t.CopyTo(It.IsAny<User[]>(), It.IsAny<int>())).Callback<User[], int>((u,c) => fakes.CopyTo(u,c));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM