简体   繁体   中英

Why is my mocked object returning no results?

I'm trying to create a mock of a DBContext and DbSet . I think I'm setting the DBContext up correctly, and in turn, the DbSet but even after I add elements to the DBSet , it's still returning null.

Am I doing something obviously wrong?

First I do the setup as follows:

[SetUp]
public void Setup_Tests()
{
    Database.SetInitializer(new DropCreateDatabaseAlways<SubscriptionManagementContext>());

    var mock = new Mock<SubscriptionManagementContext>();
    mock.Setup(xx => xx.UIElements).Returns(GetMockDBSet(SubManInitializer.GetUIElements));

    _subscriptionManagementContext = mock.Object;
}

SubscriptionManagementContext is defined as:

public class SubscriptionManagementContext : DbContext
{
    public SubscriptionManagementContext()
        : base("SubscriptionManagementContext")
    {
    }

    public virtual DbSet<UIElement> UIElements { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    }
}   

here setupAction.Invoke() should return the List<UIElement> as defined in GetUIElements()

private static DbSet<T> GetMockDBSet<T>(Func<List<T>> setupAction) where T : class
{
    var mockDBSet = new Mock<DbSet<T>>();

    mockDBSet.Setup(xx => xx.AddRange(setupAction.Invoke()));

    return mockDBSet.Object;
}   

public static List<UIElement> GetUIElements()
{
    var uiElements = new List<UIElement>
    {
        new UIElement {ElementName = "EmailDetails" },
        new UIElement {ElementName = "SFTPDetails"      },
        new UIElement {ElementName = "ScheduleDetails"  },
        new UIElement {ElementName = "FileNameElement"  },
    };
    return uiElements;
}

When I debug this test, I can see that GetUIElements() has executed, so I thought the uiElements object could contain data, but instead it throws an ArgumentNullException .

[Test]
public void Can_Get_UIElements()
{
    var uiElements = _subscriptionManagementContext.UIElements;

    Assert.IsNotNull(uiElements);

    Assert.IsTrue(uiElements.Any()); // throws System.ArgumentNullException 
}

What do I need to do to ensure uiElements will contain data?

Edit

As requested, the Stack Trace:

at System.Linq.Expressions.Expression.RequiresCanRead(Expression expression, String paramName)
at System.Linq.Expressions.Expression.ValidateOneArgument(MethodBase method, ExpressionType nodeKind, Expression arg, ParameterInfo pi)
at System.Linq.Expressions.Expression.ValidateArgumentTypes(MethodBase method, ExpressionType nodeKind, ReadOnlyCollection`1& arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, IEnumerable`1 arguments)
at System.Linq.Expressions.Expression.Call(Expression instance, MethodInfo method, Expression[] arguments)
at System.Linq.Queryable.Any[TSource](IQueryable`1 source)
at tstReportSubscriptionManagement.Test.SubManTests.Can_Get_UIElements() in c:\git\tst\tstReportSubscriptionMgmt\tstReportSubscriptionManagement.Test\SubManTests.cs:line 74

Since your mocked DbSet is meant to deal with IQueryable<T> data, AddRange is not enough to make it work like a regular List<T> .

You need to mock the missing implementation of IQueryable<T> :

private static DbSet<T> GetMockDBSet<T>(Func<List<T>> setupAction) where T : class
{
    var mockDBSet = new Mock<DbSet<T>>();
    var mockedData = setupAction.Invoke().AsQueryable();

    mockDBSet.As<IQueryable<T>>().Setup(x => x.Provider).Returns(mockedData.Provider);
    mockDBSet.As<IQueryable<T>>().Setup(x => x.Expression).Returns(mockedData.Expression);
    mockDBSet.As<IQueryable<T>>().Setup(x => x.ElementType).Returns(mockedData.ElementType);
    mockDBSet.As<IQueryable<T>>().Setup(x => x.GetEnumerator()).Returns(mockedData.GetEnumerator());

    return mockDBSet.Object;
}

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