最小起订量框架的真正目的
real purpose of moq framework
有人要求我使用 Moq 框架编写单元测试。我对如何用 C# 编写最小起订量测试还很陌生。
我正在经历这个MSDN link
这是我现在正在做的事情,因为我们在存储库上使用依赖注入
//Repository
public interface IRepo
{
IQueryable<MyModel> GetById( long userId );
}
public class Repo : BaseManager, IRepo
{
public Repo(myDbContext context)
{
dbContext = context; //dbContext is from BaseManager class
}
public IQueryable<MyModel> GetById( long userId )
{
return dbContext.MyModel.Where(x => x.IsActive && x.UserId == userId );
}
}
//Test class
public class Test
{
Mock<DbSet<MyModel>> mockSet;
Mock<myDbContext> mockContext;
Mock<IRepo> mockRepository;
[TestInitialize]
public void Setup()
{
var data = new List<MyModel>{
//3 records
}.AsQueryable();
var mockSet = new Mock<DbSet<MyModel>>();
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<myDbContext>();
mockContext.Setup(c => c.MyModel).Returns(mockSet.Object);
mockRepository = new Mock<IRepo>();
mockRepository.Setup(m => m.GetById(It.IsAny<long>())).Returns(data); //Here the GetById method is set to return all 3 records set in data object.
}
[TestMethod]
public void Test_Mock_For_Nothing()
{
var controller = new MyController(mockRepository.Object);
var result = controller.GetById(1); //this will call GetById method in the repository
Assert.AreEqual(result.Count(), 1);//This will fail as we will get count as 3
}
}
因此,尽管我模拟了上下文和存储库,但存储库中的逻辑从未执行过。由于 GetById 方法将根据虚拟数据直接 return 包含 3 条记录的结果。
我希望根据存储库方法中的逻辑过滤掉虚拟数据。最小起订量是否可行?
不执行存储库代码时使用 Moq 框架的真正目的是什么?
通过单元测试,您尝试 test/harden 您的业务逻辑。在你的存储库中不应该是任何 BL (Businesslogic)。使用你的 MOCK 框架,你会认为你不想测试。 -> 存储库 = 访问数据。
有了这个,您就可以更改获取数据(存储库)的方式,而无需对 Businesslogic/UnitTests :)
进行任何更改
PS:如果您想测试您的存储库或更多,您应该以集成测试甚至端到端测试为目标。
就您的测试而言,我会说使用模拟框架甚至进行此测试几乎没有什么好处。我的想法是:
1) 如果您有存储库,请编写集成测试,因为您想要证明您正在从 database/web 服务返回数据等
2) 在您想要测试某些业务的情况下使用 Moq 或 RhinoMocks logic/behaviour
鉴于您已经模拟了您的存储库,但没有看到控制器逻辑,我不确定您为什么需要模拟 dbContext。但实际上,通过此测试,您正在测试控制器逻辑而不是存储库,因为您模拟了存储库以及从存储库中的 GetById 返回的内容。
如果您希望在存储库中测试过滤器逻辑,您需要模拟 dbContext(正如您所做的那样)并在测试中创建一个新的具体存储库实例并测试从调用返回的数据到 GetById。
因此您模拟 dbContext.MyModel,返回您的三个项目并让 Where 调用执行过滤。
那里有很多关于使用模拟框架的有用信息,但是每个人对于应该测试什么以及在单个单元测试中应该测试的小单元的看法略有不同,经验和个人喜好是关键这里。
有人要求我使用 Moq 框架编写单元测试。我对如何用 C# 编写最小起订量测试还很陌生。
我正在经历这个MSDN link
这是我现在正在做的事情,因为我们在存储库上使用依赖注入
//Repository
public interface IRepo
{
IQueryable<MyModel> GetById( long userId );
}
public class Repo : BaseManager, IRepo
{
public Repo(myDbContext context)
{
dbContext = context; //dbContext is from BaseManager class
}
public IQueryable<MyModel> GetById( long userId )
{
return dbContext.MyModel.Where(x => x.IsActive && x.UserId == userId );
}
}
//Test class
public class Test
{
Mock<DbSet<MyModel>> mockSet;
Mock<myDbContext> mockContext;
Mock<IRepo> mockRepository;
[TestInitialize]
public void Setup()
{
var data = new List<MyModel>{
//3 records
}.AsQueryable();
var mockSet = new Mock<DbSet<MyModel>>();
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Provider).Returns(data.Provider);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.Expression).Returns(data.Expression);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.ElementType).Returns(data.ElementType);
mockSet.As<IQueryable<MyModel>>().Setup(m => m.GetEnumerator()).Returns(data.GetEnumerator());
var mockContext = new Mock<myDbContext>();
mockContext.Setup(c => c.MyModel).Returns(mockSet.Object);
mockRepository = new Mock<IRepo>();
mockRepository.Setup(m => m.GetById(It.IsAny<long>())).Returns(data); //Here the GetById method is set to return all 3 records set in data object.
}
[TestMethod]
public void Test_Mock_For_Nothing()
{
var controller = new MyController(mockRepository.Object);
var result = controller.GetById(1); //this will call GetById method in the repository
Assert.AreEqual(result.Count(), 1);//This will fail as we will get count as 3
}
}
因此,尽管我模拟了上下文和存储库,但存储库中的逻辑从未执行过。由于 GetById 方法将根据虚拟数据直接 return 包含 3 条记录的结果。
我希望根据存储库方法中的逻辑过滤掉虚拟数据。最小起订量是否可行?
不执行存储库代码时使用 Moq 框架的真正目的是什么?
通过单元测试,您尝试 test/harden 您的业务逻辑。在你的存储库中不应该是任何 BL (Businesslogic)。使用你的 MOCK 框架,你会认为你不想测试。 -> 存储库 = 访问数据。 有了这个,您就可以更改获取数据(存储库)的方式,而无需对 Businesslogic/UnitTests :)
进行任何更改PS:如果您想测试您的存储库或更多,您应该以集成测试甚至端到端测试为目标。
就您的测试而言,我会说使用模拟框架甚至进行此测试几乎没有什么好处。我的想法是:
1) 如果您有存储库,请编写集成测试,因为您想要证明您正在从 database/web 服务返回数据等
2) 在您想要测试某些业务的情况下使用 Moq 或 RhinoMocks logic/behaviour
鉴于您已经模拟了您的存储库,但没有看到控制器逻辑,我不确定您为什么需要模拟 dbContext。但实际上,通过此测试,您正在测试控制器逻辑而不是存储库,因为您模拟了存储库以及从存储库中的 GetById 返回的内容。
如果您希望在存储库中测试过滤器逻辑,您需要模拟 dbContext(正如您所做的那样)并在测试中创建一个新的具体存储库实例并测试从调用返回的数据到 GetById。
因此您模拟 dbContext.MyModel,返回您的三个项目并让 Where 调用执行过滤。
那里有很多关于使用模拟框架的有用信息,但是每个人对于应该测试什么以及在单个单元测试中应该测试的小单元的看法略有不同,经验和个人喜好是关键这里。