Per aggiungere a la risposta eccellente di emddudley il più grande guadagno che puoi ottenere nel prendere in giro il servizio è essere in grado di prova cosa dovrebbe succedere che il servizio non funzioni correttamente. Lo pseudo-codice di test potrebbe essere simile a questo:
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());
}
}
E ora la tua implementazione è stata modificata con questo nuovo requisito
public int getAge(Service s, Logger l)
{
try {
int age = s.execute(empId);
return age;
}
catch(Exception ex) {
l.LogError(ex);
throw;
}
}
In altri scenari è più probabile che tu debba rispondere a risposte più complicate. Se il servizio prevede l'elaborazione della carta di credito, è necessario rispondere a Operazione riuscita, Servizio non disponibile, Carta di credito scaduta, Numero non valido, ecc. Danneggiando il servizio è possibile garantire che risponda a questi scenari in modo appropriato per la propria situazione. In questo caso devi prendere in giro l'input / output del servizio e il feedback che ottieni dal sapere che il codice che consuma funzionerà per tutti gli output noti è davvero significativo e prezioso.
EDIT: Ho appena notato che vuoi essere in grado di prendere in giro senza modificare il metodo esistente. Per fare ciò il metodo locate("ageservice");
dovrebbe essere cambiato per supportare gli oggetti mock nei test e localizzare il servizio reale una volta che è pronto. Questa è una variante del modello di localizzazione del servizio che astrae la logica per recuperare l'implementazione del servizio che stai utilizzando. Una versione veloce potrebbe essere simile a questa:
public Service locate(string serviceToLocate) {
if(testEnvironment) // Test environment should be set externally
return MockService(serviceToLocate);
else
return Service(serviceToLocate);
}
Tuttavia, la mia raccomandazione sarebbe spostare le dipendenze del servizio in Costruttori:
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());
}
}
Ora il metodo getAge non ha più la responsabilità di cercare il servizio in quanto è stato estratto dalla classe lasciando completamente un'implementazione simile a questa:
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;
}
}