GPGVM
GPGVM

Reputation: 5619

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.

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.

What I am falling down on here is the 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?

Upvotes: 0

Views: 1446

Answers (2)

Sunny Milenov
Sunny Milenov

Reputation: 22310

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

In essence, unless a class in real POCO (i.e. only data with public setters and getters), using "new" is a killer for unit testing. I.e. 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.

Consider the following changes:

  1. Inject the RequestHelper (so you can mock the CreateResponse method)
  2. Use and inject some mapping factory of sort, which can create CarResponseObjects from Car.
  3. Consider CarResponse to implement something like IResponse, so your RequestHelper, or factory, can return interfaces.

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)

Upvotes: 1

Graham Dawes
Graham Dawes

Reputation: 229

You can use SetupGet and SetupSet to mock properties. 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.

Upvotes: 0

Related Questions