设置一个仅公开属性的模拟(Moq)class
Setup a Mocked (Moq) class that only exposes properties
我正在尝试模拟(使用最小起订量)一个 class 在 class 上设置一个 return 对象,它只公开两个属性。
在我有限的起订量经验中,我通常会使用 Setup() lamda 来定义方法调用,然后 Returns() 吐回所需的输出。
我在这里失败的是 Setup()。没有 "method" 可以调用,因为构造函数会完成工作,填充两个属性,然后 returns.
我想嘲笑的 class...显然是假的:
public class CarResponse
{
public IMetaModel meta { get; set; }
public List<ICarModel> cars { get; set; }
public CarResponse(Common.Models.Car car)
{
this.cars = new List<ICarModel>();
}
}
我微弱的嘲讽尝试:
private Mock<CarResponse> _carResponse = new Mock<CarResponse>(MockBehavior.Strict);
_carResponse.Setup( ????? ).Returns(new CarResponse() { meta = new MetaModelV2(), cars = foo });
为了进一步说明...这是我尝试为其编写单元测试的代码:
public HttpResponseMessage AddPickup()
{
//....code removed for brevity....
//this repository is mocked and returns the object exactly as I want it
var car = carRepository.GetCar(carId);
if (!errorInfo.Any()) //This check is bogus it never gets sets
{
RequestHelper rqh = new RequestHelper();
response = rqh.CreateResponse(Request, HttpStatusCode.OK, new CarResponse(car));
}
我的单元测试:
[TestMethod]
public void AddValidPickupCorrectResponse()
{
//arrange
//...lots of code here left off for setting up http context etc
//act---
var response = controller.AddPickup();
//assert
}
如果我按照建议使用固定对象,我将如何 "hook" 将其用于测试代码。例如,我编写了一个单元测试,它使用我的预装对象而不是最小起订量,但是如何让 SUT 使用该预装对象?
您可以使用 SetupGet 和 SetupSet 模拟属性。但是,我不认为你可以模拟具体 类.
如果您正在处理值类型,您可能会发现更容易不去打扰模拟,而只使用预制对象。
很少有问题会妨碍对上述代码进行正确的单元测试:
- 新建响应助手
- 更新 CarResponseObject
本质上,除非真正的 POCO 中的 class(即只有具有 public setter 和 getter 的数据),否则使用 "new" 是单元测试的杀手。 IE。它不是单元测试(单独测试 unit/method)。它测试 CarResponse ctor 的行为,以及 RequestHelper 的工作。
考虑以下更改:
- 注入 RequestHelper(这样你就可以模拟 CreateResponse 方法)
- 使用并注入一些映射工厂,它可以从 Car 创建 CarResponseObjects。
- 考虑 CarResponse 来实现类似 IResponse 的功能,这样您的 RequestHelper 或工厂就可以 return 接口。
有了以上所有内容,您的测试将如下所示(伪代码,不完整):
//arrange
//....
var carInDB = new Car();
_repoMock.Setup(...).Returns(car);
var carResponse = Mock.Of<IResponse>();
_mapperMock.Setup(m=>m.CreateResponse(car).Returns(carResponse);
var responseFromHelper = new WhateverResponseIsNeeded(); //(or create a new mock IResponse - note! new mock, different than car response
_helperMock.Setup(_controller.Request, HttpStatusCode.OK, carResponse).Returns(responseFromHelper);
//act
var response = _controller.AddPickup();
//assert
response.Should().Be.SameInstanceAs(responseFromHelper)
我正在尝试模拟(使用最小起订量)一个 class 在 class 上设置一个 return 对象,它只公开两个属性。
在我有限的起订量经验中,我通常会使用 Setup() lamda 来定义方法调用,然后 Returns() 吐回所需的输出。
我在这里失败的是 Setup()。没有 "method" 可以调用,因为构造函数会完成工作,填充两个属性,然后 returns.
我想嘲笑的 class...显然是假的:
public class CarResponse
{
public IMetaModel meta { get; set; }
public List<ICarModel> cars { get; set; }
public CarResponse(Common.Models.Car car)
{
this.cars = new List<ICarModel>();
}
}
我微弱的嘲讽尝试:
private Mock<CarResponse> _carResponse = new Mock<CarResponse>(MockBehavior.Strict);
_carResponse.Setup( ????? ).Returns(new CarResponse() { meta = new MetaModelV2(), cars = foo });
为了进一步说明...这是我尝试为其编写单元测试的代码:
public HttpResponseMessage AddPickup()
{
//....code removed for brevity....
//this repository is mocked and returns the object exactly as I want it
var car = carRepository.GetCar(carId);
if (!errorInfo.Any()) //This check is bogus it never gets sets
{
RequestHelper rqh = new RequestHelper();
response = rqh.CreateResponse(Request, HttpStatusCode.OK, new CarResponse(car));
}
我的单元测试:
[TestMethod]
public void AddValidPickupCorrectResponse()
{
//arrange
//...lots of code here left off for setting up http context etc
//act---
var response = controller.AddPickup();
//assert
}
如果我按照建议使用固定对象,我将如何 "hook" 将其用于测试代码。例如,我编写了一个单元测试,它使用我的预装对象而不是最小起订量,但是如何让 SUT 使用该预装对象?
您可以使用 SetupGet 和 SetupSet 模拟属性。但是,我不认为你可以模拟具体 类.
如果您正在处理值类型,您可能会发现更容易不去打扰模拟,而只使用预制对象。
很少有问题会妨碍对上述代码进行正确的单元测试:
- 新建响应助手
- 更新 CarResponseObject
本质上,除非真正的 POCO 中的 class(即只有具有 public setter 和 getter 的数据),否则使用 "new" 是单元测试的杀手。 IE。它不是单元测试(单独测试 unit/method)。它测试 CarResponse ctor 的行为,以及 RequestHelper 的工作。
考虑以下更改:
- 注入 RequestHelper(这样你就可以模拟 CreateResponse 方法)
- 使用并注入一些映射工厂,它可以从 Car 创建 CarResponseObjects。
- 考虑 CarResponse 来实现类似 IResponse 的功能,这样您的 RequestHelper 或工厂就可以 return 接口。
有了以上所有内容,您的测试将如下所示(伪代码,不完整):
//arrange
//....
var carInDB = new Car();
_repoMock.Setup(...).Returns(car);
var carResponse = Mock.Of<IResponse>();
_mapperMock.Setup(m=>m.CreateResponse(car).Returns(carResponse);
var responseFromHelper = new WhateverResponseIsNeeded(); //(or create a new mock IResponse - note! new mock, different than car response
_helperMock.Setup(_controller.Request, HttpStatusCode.OK, carResponse).Returns(responseFromHelper);
//act
var response = _controller.AddPickup();
//assert
response.Should().Be.SameInstanceAs(responseFromHelper)