简体   繁体   English

设置仅公开属性的模拟(Moq)类

[英]Setup a Mocked (Moq) class that only exposes properties

I am trying to mock (using Moq) a class set a return object on a class that only exposes two properties. 我试图模拟(使用Moq)一个类,该类在仅公开两个属性的类上设置了一个返回对象。

In my limited Moq experience I would normally use a Setup() lamda to define the method call and then Returns() to spit back the desired output. 以我有限的Moq经验,我通常会使用Setup()lamda定义方法调用,然后使用Return()吐回所需的输出。

What I am falling down on here is the Setup(). 我在这里跌倒的是Setup()。 There isn't a "method" to call as the constructor does the work, populates the two properties and then returns. 当构造函数完成工作,填充两个属性然后返回时,没有“方法”可调用。

My class that I want to mock...obviously dummied down: 我想嘲笑的课...显然是哑巴了:

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>();
    }
}

My feeble attempt at mocking: 我微不足道的嘲笑尝试:

private Mock<CarResponse> _carResponse = new Mock<CarResponse>(MockBehavior.Strict);
_carResponse.Setup( ????? ).Returns(new CarResponse() { meta = new MetaModelV2(), cars = foo });

To further clarify...here is the code I am trying to write a unit test for: 为了进一步澄清...这是我正在尝试为以下单元编写单元测试的代码:

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));
}

My unit test: 我的单元测试:

[TestMethod]
public void AddValidPickupCorrectResponse()
{
   //arrange
   //...lots of code here left off for setting up http context etc

  //act---
  var response = controller.AddPickup();

  //assert

}

If I were to use a precanned object as suggested how would I "hook" it to the code under test. 如果我按照建议使用预设的对象,该如何将其“挂钩”到要测试的代码。 For example I write a unit test that uses my pre-canned object instead of a Moq but how do I get that pre-canned object to be used by the SUT? 例如,我编写了一个使用我的预设对象而不是Moq的单元测试,但是如何获取该预设对象供SUT使用?

There are few problems which can get in the way of properly unit testing the above code: 正确地对上述代码进行单元测试的问题很少:

  1. new-ing up the response helper 新的响应助手
  2. new-ing up the CarResponseObject 更新CarResponseObject

In essence, unless a class in real POCO (ie only data with public setters and getters), using "new" is a killer for unit testing. 从本质上讲,除非是真正的POCO中的类(即仅包含公共设置者和获取者的数据),否则使用“ new”是单元测试的杀手er。 Ie it is not a unit test (test the unit/method in isolation). 也就是说,它不是单元测试(单独测试单元/方法)。 It tests the behavior of the CarResponse ctor, as well as the working of RequestHelper. 它测试CarResponse ctor的行为以及RequestHelper的工作。

Consider the following changes: 请考虑以下更改:

  1. Inject the RequestHelper (so you can mock the CreateResponse method) 注入RequestHelper(以便您可以模拟CreateResponse方法)
  2. Use and inject some mapping factory of sort, which can create CarResponseObjects from Car. 使用并注入某种映射工厂,可以从Car创建CarResponseObjects。
  3. Consider CarResponse to implement something like IResponse, so your RequestHelper, or factory, can return interfaces. 考虑使用CarResponse实现类似于IResponse的东西,以便您的RequestHelper或工厂可以返回接口。

With all of the above, your test will look like (pseudo code, not complete): 通过以上所有操作,您的测试将看起来像(伪代码,未完成):

//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)

You can use SetupGet and SetupSet to mock properties. 您可以使用SetupGet和SetupSet来模拟性能。 However, I don't think you can mock concrete classes. 但是,我认为您不能模拟具体的类。

If you are dealing with a value type you might find it easier to not bother mocking and just used a pre-canned object. 如果您要处理的是值类型,则可能会发现不打扰并且只使用预先罐头的对象会更容易。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM