为什么我的模拟对象没有返回任何结果?
Why is my mocked object returning no results?
我正在尝试创建 DBContext
和 DbSet
的模拟。我想我正确地设置了 DBContext
,然后设置了 DbSet
,但即使在我将元素添加到 DBSet
之后,它仍然是 returning null。
我做错了什么吗?
首先我进行如下设置:
[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
定义为:
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>();
}
}
这里 setupAction.Invoke()
应该 return List<UIElement>
定义在 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;
}
当我调试这个测试时,我可以看到 GetUIElements()
已经执行,所以我认为 uiElements
对象可能包含数据,但它抛出一个 ArgumentNullException
.
[Test]
public void Can_Get_UIElements()
{
var uiElements = _subscriptionManagementContext.UIElements;
Assert.IsNotNull(uiElements);
Assert.IsTrue(uiElements.Any()); // throws System.ArgumentNullException
}
我需要做什么才能确保 uiElements
包含数据?
编辑
根据要求,堆栈跟踪:
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
由于您的模拟 DbSet
旨在处理 IQueryable<T>
数据,因此 AddRange
不足以使其像常规 List<T>
一样工作。
您需要模拟缺少的 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;
}
我正在尝试创建 DBContext
和 DbSet
的模拟。我想我正确地设置了 DBContext
,然后设置了 DbSet
,但即使在我将元素添加到 DBSet
之后,它仍然是 returning null。
我做错了什么吗?
首先我进行如下设置:
[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
定义为:
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>();
}
}
这里 setupAction.Invoke()
应该 return List<UIElement>
定义在 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;
}
当我调试这个测试时,我可以看到 GetUIElements()
已经执行,所以我认为 uiElements
对象可能包含数据,但它抛出一个 ArgumentNullException
.
[Test]
public void Can_Get_UIElements()
{
var uiElements = _subscriptionManagementContext.UIElements;
Assert.IsNotNull(uiElements);
Assert.IsTrue(uiElements.Any()); // throws System.ArgumentNullException
}
我需要做什么才能确保 uiElements
包含数据?
编辑
根据要求,堆栈跟踪:
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
由于您的模拟 DbSet
旨在处理 IQueryable<T>
数据,因此 AddRange
不足以使其像常规 List<T>
一样工作。
您需要模拟缺少的 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;
}