首先,ObjectResult没有公共无参数构造函数,因此需要首先为ObjectResult创建一个可测试的包装器。 @forsvarir 的回答(https://stackoverflow.com/users/592182/forsvarir https://stackoverflow.com/users/592182/forsvarir)在这篇文章中让我沿着这些思路正确思考(EF6 - 无法模拟 ObjectResult 的返回值以进行单元测试 https://stackoverflow.com/questions/31079558/ef6-cannot-mock-return-value-for-objectresultt-for-unit-test):
using System.Data.Entity.Core.Objects;
namespace MyNamespace.Mocks
{
public class TestableEfObjectResult<T> : ObjectResult<T> { }
}
当然,DbContext需要被mock。然后需要设置您的方法以返回适当的模拟枚举器。为了方便起见,我创建了一种方法来帮助创建模拟 EF 结果,以防止我的测试代码变得混乱和冗余。这可以存在于您用于测试的一些实用类中,尽管我只是将其作为私有方法包含在这里。这里的关键是,当调用 GetEnumerator 时,模拟对象结果需要返回一个枚举器:
namespace MyNamespace.Mocks
{
public class MockSomeDbEntities
{
public static Mock<SomeDbEntities> Default
{
get
{
var mockSomeDbEntities = new Mock<SomeDbEntities>();
mockSomeDbEntities
.Setup(e => e.SomeMethod(It.IsAny<int>()))
.Returns(MockEfResult(Enumerators.SomeCollection).Object);
return mockSomeDbEntities;
}
}
private static Mock<TestableEfObjectResult<T>> MockEfResult<T>(Func<IEnumerator<T>> enumerator) where T : class
{
var mock = new Mock<TestableEfObjectResult<T>>();
mock.Setup(m => m.GetEnumerator()).Returns(enumerator);
return mock;
}
}
}
我创建的 Enumerators 类用于在模拟上调用函数时交回枚举器,如下所示。在此示例中,我使用假枚举器创建 5 行数据:
using System;
using System.Collections.Generic;
namespace MyNamespace.FakeData
{
public static class Enumerators
{
public static IEnumerator<Some_Result> SomeCollection()
{
yield return FakeSomeResult.Create(1);
yield return FakeSomeResult.Create(2);
yield return FakeSomeResult.Create(3);
yield return FakeSomeResult.Create(4);
yield return FakeSomeResult.Create(5);
}
}
}
而且,正如您所看到的,这仅依赖于一个创建每个假数据行的类:
namespace MyNamespace.FakeData
{
public static class FakeSomeResult
{
public static Some_Result Create(int id)
{
return new Some_Result
{
Id = id,
};
}
}
}
能够在这个级别进行模拟确实使我能够进行 BDD,并且只模拟或伪造外围设备,而从不模拟或伪造my code,所以我得到了完整的测试覆盖率。
希望这对那些像我一样正在寻找一种干净的方式来模拟 Entity Framework 6 的人有所帮助。