简体   繁体   中英

How to mock a method inside the same class being tested?

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?

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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