views:

25

answers:

3

I have a method that calls a service to retrieve an instance of an object, updates the instance then saves the instance back to the service (the code for this is below).

What I want to know is if there is a nice way in Moq to check the following:-

  1. That the instance that is being saved back to the service is a modified version of the original instance
  2. That the instance has been updated as desired

I know I can use It.Is<MyThing>(x => x.Name == newName) to check for point 2 here. Doing this ignores point 1 though.

Is there a clean way to achieve this?

CLASS CODE:

public class MyClass
{
    private readonly IThingService thingService;

    public MyClass(IThingService thingService)
    {
        this.thingService = thingService;
    }

    public void SaveMyThing(MyThing myThing)
    {
        var existingThing = thingService.Get(myThing.Id);
        existingThing.Name = myThing.Name;
        thingService.Save(existingThing);
    }
}

public class MyThing
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IThingService
{
    MyThing Get(int id);
    void Save(MyThing myThing);
}

TEST CODE:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService);
    thingService
        .Setup(ts => ts.Save(**UPDATED-THING-FROM-SERVICE**))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}
+1  A: 

You are almost there:

[Test]
public void Save_NewName_UpdatedThingIsSavedToService()
{
    // Arrange
    var myThing = new MyThing { 
                                Id = 42,
                                Name = "Thing1"
                            };
    var thingFromService = new MyThing
                    {
                        Id = 42,
                        Name = "Thing2"
                    };

    var thingService = new Mock<IThingService>();
    thingService
        .Setup(ts => ts.Get(myThing.Id))
        .Returns(thingFromService)
        .Verifiable();
    thingService
        .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
        .Verifiable();

    var myClass = new MyClass(thingService.Object);

    // Act
    myClass.SaveMyThing(myThing);

    // Assert
    thingService.Verify();
}

The main difference is that I also added a call to Verifiable() to the first Setup, and then I added the It.Is check you already mentioned in your answer. Because of the predicate, the Save method will only be matched when the predicate evaluates to true, in which case the Verify call succeeds.

However, this test actually tests two things (Get and Save). To avoid Assertion Roulette, it would be better to split it up into two tests.

Mark Seemann
Yep, I understand this. Effectively the "Get" call to thingService is a Stub (rather than a mock) and hence why it doesn't need a .Verify().The issue with this code is that it doesn't differentiate between passing an updated version of the "thingFromService" instance to the Save method and just passing the MyThing instance passed in to the SaveMyThing method (point 1 in my question). :-(
Russell Giddings
+1  A: 

If I understand correctly, you want to verify that the parameter passed to ts.Save is the instance returned from the service.

If that's true, check reference equality in addition to verifying that the Name value meets your expectations:

thingService
     .Setup(ts => ts.Save(It.Is<MyThing>(thing => thing == thingFromService
                                               && thing.Name = myThing.Name))
     .Verifiable();
Jeff Sternal
Fantastic! I expected "thing == thingFromService" to return false as "thing.Name != thingFromService.Name". That's not the case though as the thingFromService is the object getting updated in the method under test therefore is the same. It's been a long day ;-) Thanks Jeff!
Russell Giddings
A: 

I agree with Mark's answer but a bit confused by your first statement. Are you trying to find out if the object is the same object reference or object type? The It.Is just makes sure that parameter is the type of MyThing, not that it is the actual reference to your previous object.

If you want to intercept the value being passed to your mock service than you could use a callback like below and then do whatever assertions you want on the result object:

MyThing result = null;

thingService
    .Setup(ts => ts.Save(It.Is<MyThing>(x => x.Name == myThing.Name)))
    .Callback((MyThing saved) => result = saved)
    .Verifiable();
Greg Roberts
I want to check that it is the same object reference with an updated property
Russell Giddings