3

I am new to MoQ framework. I am writing unit testing for controller using MoQ framework and here is my test method,

var mockedItemDetail = new ItemDetail()
        {
            Name = null
        };

        var mockObject = new Mock<IItem>();
        mockObject.Setup(x => x.GetItemDetail()).Returns(mockedItemDetail);

        var result = myController.GetDetails() as ViewResult;

Here is my Controller Method,

public ActionResult GetDetails()
    {
        var controllerItemDetail = new ItemDetail();
        controllerItemDetail = _item.GetItemDetail();
        controllerItemDetail.Name = "Changed Name";
        return View("ViewName", controllerItemDetail);
    }

Test runs and now I want to assert the sent mockedItemDetail and received model result controllerItemDetail.

In above case, mockedItemDetail property "Name" has null and received controllerItemDetail property Name as "Changed Name".

But whenever I debug, after calling the test method GetDetails(),

  1. My mockedItemDetail property Name is also updated as "Changed Name" in the current scope and I don't know why? Is this is the actual behavior of MoQ?

Edited Content

Consider the same above case in below mock list, here the change in the mock object will not update in all contexts. i.e. The list count for mockedItemDetailList remains 0 and the list count of controllerItemDetail is 1 even after test method calls. Why?

Test method:

var mockedItemDetailList = new List<ItemDetail>();

    var mockObject = new Mock<IItem>();
    mockObject.Setup(x => x.GetListOfItemDetail()).Returns(mockedItemDetailList);

    var result = myController.GetDetails() as ViewResult;

Controller method:

    public ActionResult GetDetails()
{
    var controllerItemDetail = new ItemDetail();
    controllerItemDetail = _item.GetListOfItemDetail();
    controllerItemDetail.Add(new ItemDetail(){
    Name = "Changed Name"
    });
    return View("ViewName", controllerItemDetail);
}
Praveen
  • 831
  • 7
  • 15
  • 2
    You're returning a specific object for `x.GetItemDetail()`. Why would it not update in the current context? That object is being modified at `controllerItemDetail.Name = "Changed Name";`. This is intended behavior. – Blue Jul 07 '17 at 06:00
  • Mockling is a sin –  Jul 07 '17 at 06:20
  • Please find the edited content @FrankerZ – Praveen Jul 07 '17 at 06:41
  • Based on the code you've posted I agree with @FrankerZ, that is the intended behaviour (and it is also the expected behaviour in the 2nd example, both variables refer to the same instance of the list so the list should have an object added ). However it is hard to tell from your posted code how the mocked object(s) are injected into your controller. Are you passing the mocked object (IItem) into the constructor of your controller? – Mats Björkman Eldh Jul 07 '17 at 08:11

1 Answers1

2

You have a very specific object:

var mockedItemDetail = new ItemDetail()
{
    Name = null
};

When you call mockObject.Setup(x => x.GetItemDetail()).Returns(mockedItemDetail);, you're returning the reference to mockItemDetail. Any changes on that object will update in all contexts.

A quick follow up. To have it return a blank new ItemDetail() each time, you can simply use the lambda method of Returns():

mockObject.Setup(x => x.GetItemDetail()).Returns(() => new ItemDetail()
{
    Name = null
});
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Blue
  • 22,608
  • 7
  • 62
  • 92
  • I agree with your point. But please explain me the reason for edited content? – Praveen Jul 07 '17 at 06:44
  • To give you an alternative, if you wanted each `GetItemDetail()` to return a new instance and not effect other versions of `ItemDetail()`'s that may be returned. – Blue Jul 07 '17 at 11:53
  • It seems like you just gave an alternative solution. But i want to know why the same instance is updated in first case and not updated in second case(Incase of lists)? – Praveen Jul 07 '17 at 12:42
  • Because you're returning a new `ItemDetail` every time the lambada function is run. Calling `mockObject.Object.GetItemDetail()` would then call the anonymous function (lambada) which would generate a new `ItemDetail` and return it, versus (In the first example), returning the same specific object. – Blue Jul 07 '17 at 12:49