此question向我展示了如何模拟在构造函数中具有参数的类。这是Mock.Of<>
上的nice block post,但没有显示如何使用函数语法模拟构造函数。
public class MyClass
{
public MyClass(IDependency1 dep1, IDependency2 dep2, IDependency3 dep3)
{}
public ReturnType MyNewMethod(Tyep1 t1, Type2 t2)
{
//1. call to ExistingMethod1();
//2. call to ExistingMethod2();
//3. call using the DbContext
//4. call using the Logger
}
}
我从第一篇博客文章中得到了类似的东西。
var dep1 = new Mock<IDependency1>();
var dep2 = new Mock<IDependency2>();
var dep3 = new Mock<IDependency3>();
object[] arrParams = { dep1.Object, dep2.Object, dep3.Object }
var sut = new Mock<MyClass>(arrParams);
那么如何使用Mock.Of<>
语法模拟在构造函数中具有参数的类?
新方法不仅会调用现有方法,而且还会访问DbContext
,logger
以及其他服务。因此,除了要测试的方法之外,我还需要模拟其他所有内容。
public class MyClass
{
public MyClass(MyDbContext context, ISecurityService secService, ILogger logger)
{}
public ReturnType1 ExistingMethod1(Type1 t1){}
public ReturnType2 ExistingMethod2(Type t){}
public MyEntity MyNewMethod(Tyep1 t1, Type2 t2)
{
//1. call to ExistingMethod1(); --> I'll just setup the return value
//2. call to ExistingMethod2(); --> I'll just setup the return value
//3. call using the DbContext --> ???
//4. call using the Logger --> ???
var x = ExistingMethod1(t1); //1.
var y = ExistingMethod1(x); //2.
var result context.MyEntities. //3.
.Where(e => e.id == y.MyEntityId)
.ToList();
return result;
}
}
答案 0 :(得分:2)
用Moq进行模拟需要模拟该类以使其具有虚拟方法,或者您可以模拟任何接口。当您使用moq进行模拟时,它将动态创建一个动态实现,因此它不依赖于您的实现。就您而言,您可以做
public class MyClass
{
public MyClass(IDependency1 dep1, IDependency2 dep2, IDependency3 dep3)
{}
public ReturnType MyNewMethod(Tyep1 t1, Type2 t2)
{
//1. call to ExistingMethod1(); --> I'll just setup the return value
//2. call to ExistingMethod2(); --> I'll just setup the return value
//3. call using the DbContext --> ???
//4. call using the Logger --> ???
}
}
Mock<MyClass> mockedObj = new Mock<MyClass>();
mockedObj.SetUp(x=>x.MyNewMethod()).Returns(objectOfReturnType);
在这里您需要将MyNewMethod虚拟化。 return objectOfReturnType是您创建为测试对象的对象。因此不需要或不需要您的方法主体详细信息。那就是模拟的想法,您正在用假的实现(在本例中是安装程序)来模拟实际的实现。您可以根据测试被测类的方式来改变不同的返回对象。我建议您先阅读单元测试101。
请注意,您正在设置MyNewMethod的行为。您的实现可能会做很多事情,但是您关心的是它的回报。这就是为什么该方法也必须是虚拟的,它会被Moq覆盖并返回您刚刚设置的内容。在内部,该方法可能调用不同的内容...所以您不在乎
您还应该阅读Moq的基础知识,您可以在这里https://github.com/Moq/moq4/wiki/Quickstart
答案 1 :(得分:1)
如果要测试MyClass
,则可能要模拟依赖项:
// Arrange
var mockDep1 = new Mock<IDependency1>();
var mockDep2 = new Mock<IDependency2>();
var mockDep3 = new Mock<IDependency3>();
var myTestInstance = new MyClass(mockDep1.Object, mockDep2.Object, mockDep3.Object);
// Act
var result = myTestInstance.DoSomething();
// Assert
Assert.AreEqual(result, myExpectedResult); // check the direct result
mockDep1.Verify(mock => mock.SomeMethodOnMock(It.IsAny<string>()), Times.Once); // SomeMethodOnMock was called once
// ... etc
另一方面,如果 MyClass
是您要模拟另一个测试对象的依赖项,那么从中提取接口的最佳方法(例如{{1} }),以便您以更简洁的方式测试您的课程。
Moq允许您模拟非密封的类,但是如果没有其他方法,这是一种故障保护,因为在测试期间可能会执行许多无关的代码,并且您只能设置/验证非密封的虚拟或抽象成员