XUnit 如何对业务对象进行单元测试,我应该模拟所有内容吗?
XUnit how to unit test business object and should I be mocking everything?
我正在尝试对我的业务对象进行单元测试 (XUnit),它需要 2 个参数并在返回输出之前执行一些操作。
public OutPutModel MyBusinessObject(InputModel1 obj1, InputModel2 obj2)
{
// Performing some actions here including seding a call
// to the data access layer to perform some db operation.
return outPutModel;
}
在我的 XUnit 中,我正在执行以下操作
[Fact]
public void MyBusinessObject_ReturnsOutPutModel()
{
var businessObjectMock = new Mock<IBusinessObject>();
var obj1 = new Mock<InputModel1>();
var obj2 = new Mock<InputModel2>();
var outPutModel = new OutPutModel();
var result = businessObjectMock.Setup(x => x.MyBusinessObject(obj1.Object, obj2.Object)).Returns(outPutModel);
result.Equals(outPutModel);
}
现在,我在我的业务对象中设置了一个断点 (public OutPutModel MyBusinessObject(InputModel1 obj1, InputModel2 obj2))。在 运行 测试后,它没有达到断点但仍然通过测试。我在这里做错了吗?我应该模拟包括业务对象接口在内的所有内容,还是只模拟参数对象并调用业务对象的新实例?
P.S。忘了提,我知道在业务对象中包含数据库级别的东西不是一个好主意。不幸的是,想想我别无选择。
您使用的模拟框架有误。您似乎也在尝试模拟被测系统。
经验法则,只模拟绝对必要的东西,并且只有在使用实现产生连锁反应的情况下才模拟
例如,如果 BusinessObject
像您在代码注释中指出的那样依赖于数据访问层,
public class BusinessObject: IBusinessObject{
private readonly IDataAccess dataAccess;
public BusinessObject(IDataAccess dataAccess) {
this.dataAccess = dataAccess;
}
public OutPutModel SomeBusinessMethod(InputModel1 obj1, InputModel2 obj2) {
// Performing some actions here including seding a call
// to the data access layer to perform some db operation.
var outPutModel = dataAccess.SomeMethod(obj1, obj2);
return outPutModel;
}
}
您将模拟在被测方法中使用的依赖项,然后调用被测 class 的实际实例。
例如
[Fact]
public void MyBusinessObject_ReturnsOutPutModel() {
//Arrange
var expected = new OutPutModel {
// populate as needed
}
//mock the dependency
var dataAccessMock = new Mock<IDataAccess>();
//Setup the mocked dependency
dataAccessMock
.Setup(_ => _.SomeMethod(It.IsAny<InputModel1>(), It.IsAny<InputModel2>()))
.Returns(expected);
//inject the dependency into the subject under test
var businessObject = new BusinessObject(dataAccessMock.Object);
//needed objects for the test
var obj1 = new InputModel1 {
//populate as needed
};
var obj2 = new InputModel2 {
//populate as needed
};
//Act
var actual = businessObject.SomeBusinessMethod(obj1, obj2);
//Assert
Assert.AreEqual(expected, actual);
}
我正在尝试对我的业务对象进行单元测试 (XUnit),它需要 2 个参数并在返回输出之前执行一些操作。
public OutPutModel MyBusinessObject(InputModel1 obj1, InputModel2 obj2)
{
// Performing some actions here including seding a call
// to the data access layer to perform some db operation.
return outPutModel;
}
在我的 XUnit 中,我正在执行以下操作
[Fact]
public void MyBusinessObject_ReturnsOutPutModel()
{
var businessObjectMock = new Mock<IBusinessObject>();
var obj1 = new Mock<InputModel1>();
var obj2 = new Mock<InputModel2>();
var outPutModel = new OutPutModel();
var result = businessObjectMock.Setup(x => x.MyBusinessObject(obj1.Object, obj2.Object)).Returns(outPutModel);
result.Equals(outPutModel);
}
现在,我在我的业务对象中设置了一个断点 (public OutPutModel MyBusinessObject(InputModel1 obj1, InputModel2 obj2))。在 运行 测试后,它没有达到断点但仍然通过测试。我在这里做错了吗?我应该模拟包括业务对象接口在内的所有内容,还是只模拟参数对象并调用业务对象的新实例? P.S。忘了提,我知道在业务对象中包含数据库级别的东西不是一个好主意。不幸的是,想想我别无选择。
您使用的模拟框架有误。您似乎也在尝试模拟被测系统。
经验法则,只模拟绝对必要的东西,并且只有在使用实现产生连锁反应的情况下才模拟
例如,如果 BusinessObject
像您在代码注释中指出的那样依赖于数据访问层,
public class BusinessObject: IBusinessObject{
private readonly IDataAccess dataAccess;
public BusinessObject(IDataAccess dataAccess) {
this.dataAccess = dataAccess;
}
public OutPutModel SomeBusinessMethod(InputModel1 obj1, InputModel2 obj2) {
// Performing some actions here including seding a call
// to the data access layer to perform some db operation.
var outPutModel = dataAccess.SomeMethod(obj1, obj2);
return outPutModel;
}
}
您将模拟在被测方法中使用的依赖项,然后调用被测 class 的实际实例。
例如
[Fact]
public void MyBusinessObject_ReturnsOutPutModel() {
//Arrange
var expected = new OutPutModel {
// populate as needed
}
//mock the dependency
var dataAccessMock = new Mock<IDataAccess>();
//Setup the mocked dependency
dataAccessMock
.Setup(_ => _.SomeMethod(It.IsAny<InputModel1>(), It.IsAny<InputModel2>()))
.Returns(expected);
//inject the dependency into the subject under test
var businessObject = new BusinessObject(dataAccessMock.Object);
//needed objects for the test
var obj1 = new InputModel1 {
//populate as needed
};
var obj2 = new InputModel2 {
//populate as needed
};
//Act
var actual = businessObject.SomeBusinessMethod(obj1, obj2);
//Assert
Assert.AreEqual(expected, actual);
}