0

I am creating some unit tests for a method ValidateObject in a service ObjectService. The ValidateObject method calls another method ValidateObjectPropertyB. I want to mock the calls to the last method.

The ObjectService and relevant method look like this:

public class ObjectService : IObjectService
{
    public bool ValidateObject(object objectToValidate)
    {
        return 
            !String.IsNullOrEmpty(objectToValidate.PropertyA) &&
            ValidateObjectPropertyB(objectToValidate.PropertyB, currentUserId);
    }

    public bool ValidateObjectPropertyB(long propertyB, long userId)
    {
        return validationResult;
    }
}

Right now my Test class ObjectServiceTest contains the following code:

public class ObjectServiceTest
{
    var objectToValidate = new Object(validPropertyA, validPropertyB);

    using(var mock = new AutoMock.GetStrict())
    {
        var mockObjectService = new Mock<IObjectService>();
        mockObjectService.callBase = true;
        mockObjectService.Setup(s => s.ValidateObjectPropertyB(objectToValidate.PropertyB, _user.Id)).Returns(true);

        var service = mock.Create<ObjectService>();
        var result = service.ValidateObject(objectTovalidate);

        Assert.IsTrue(result);
    }
}

The above test fails because result is false, the for PropertyA succeeds What am I doing wrong?

Bunnynut
  • 1,156
  • 5
  • 14
  • 37
  • 4
    If it calls another method in the same class - just let it! Don't mock it. – mason Jun 01 '18 at 14:43
  • You're right! I was making it way too complicated. – Bunnynut Jun 01 '18 at 14:51
  • Just create a method that does the string.IsNullOrEmpty check and write a test on it. – Carra Jun 01 '18 at 14:52
  • You don't need mock at all. Mock only dependencies which makes tests slow to execute, usually this is tests which access external resources (database, webservices etc.) – Fabio Jun 02 '18 at 19:35
  • For more background on when to mock and when not, see https://stackoverflow.com/questions/56078171/when-to-use-mock-objects-in-unit-tests/56102108#56102108 – Dirk Herrmann Sep 04 '19 at 20:55

1 Answers1

0

ValidateObject works in part by calling ValidateObjectPropertyB. I am presuming you are wanting to mock this second method so that you can demonstrate that ValidateObject does indeed call ValidateObjectPropertyB (provided !String.IsNullOrEmpty(objectToValidate.PropertyA) evaluates to true)

If this is the case then you are testing implementation detail, which generally you shouldn't do. Consider a function that took two integer values and returned their sum, you would want to verify that when this function was passed 3 and 5 it returned 8, you should not test that it arrived at this answer by using a particular method/class under the hood because this is not relevant to the desired outcome and should in future you decide you wished to refactor your code the test would likely start failing even if the code still returned the desired result.

Looking at your code, it seems that return value of ValidateObject is not directly dependent on the method call to ValidateObjectPropertyB but rather the value of validationResult. It is this value that you must set to properly test ValidateObject.

One way to achieve what you are asking would be to make ValidateObjectPropertyB virtual, then create a derived class that overrides this method to return what ever you want. However I do not recommend doing this purely for the sake of unit testing.

mark_h
  • 5,233
  • 4
  • 36
  • 52