To add on to emddudley's excellent answer the biggest gain you can get in mocking the service is being able to test what should happen the service doesn't function correctly. The test pseudo-code could look something like this:
public int AgeMinimumValue_LogsServiceError_Test()
{
ClassUnderTest uut = new ClassUnderTest();
MockService service = new MockService();
service.Throws(new TimeoutException());
MockLogger logger = new MockLogger();
try {
int age = uut.getAge(service, logger);
Assert.Fail("Exception was not raised by the class under test");
}
catch (TimeoutException) {
Assert(logger.LogError().WasCalled());
}
}
And now your implementation has been edited with this new requirement
public int getAge(Service s, Logger l)
{
try {
int age = s.execute(empId);
return age;
}
catch(Exception ex) {
l.LogError(ex);
throw;
}
}
In other scenarios it is more likely that you would need to respond to more complicated responses. If the service provided credit card processing you would need to respond to Success, Service Unavailable, Expired Credit Card, Invalid Number, etc. By mocking the service you can ensure you respond to these scenarios in a way that is proper for your situation. In this case you must mock the input/output from the service and the feedback you get from knowing that the consuming code will work for all known outputs is indeed meaningful and valuable.
EDIT: I just noticed you want to be able to mock without modifying the existing method. To do this the locate("ageservice");
method would need to be changed to support mock objects in tests, and locating the real service once it is ready. This is a variation of the service locator patter which abstracts away the logic to retrieve the implementation of the service you are using. A quick version of that may look like this:
public Service locate(string serviceToLocate) {
if(testEnvironment) // Test environment should be set externally
return MockService(serviceToLocate);
else
return Service(serviceToLocate);
}
My recommendation however would be to move the service dependencies into the Constructors:
public int AgeMinimumValue_LogsServiceError_Test()
{
MockService service = new MockService();
service.Throws(new TimeoutException());
MockLogger logger = new MockLogger();
ClassUnderTest uut = new ClassUnderTest(service, logger);
try {
int age = uut.getAge();
Assert.Fail("Exception was not raised by the class under test");
}
catch (TimeoutException) {
Assert(logger.LogError().WasCalled());
}
}
Now the getAge method no longer has the responsibility of looking up the service as it has been abstracted out of the class completely leaving an implementation similar to this:
public int getAge()
{
try {
// _service is a private field set by the constructor
int age = _service.execute(empId);
return age;
}
catch(Exception ex) {
// _logger is a private field set by the constructor
_logger.LogError(ex);
throw;
}
}