Currently I have 3 service classes, they all have a similar pattern, and I need to make a 4th service class which amalgamates the functionality of the other three.
Current three classes
public class PersonService : IPersonService
{
public PersonServiceResult CreatePerson(CreatePersonParams createPersonParams)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
// [code]
unitOfWork.Commit();
return new PersonServiceResult(...);
}
}
}
public class OrderService : IOrderService
{
public OrderServiceResult CreateOrder(
int personId,
IEnumerable<PurchaseItem> items)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
// [code]
unitOfWork.Commit();
return new OrderServiceResult(...);
}
}
}
public class PaymentProcessingService : IPaymentProcessingService
{
public PaymentResult ProcessPayment(int orderId, CreditCard creditCard)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
// [code]
unitOfWork.Commit();
return new PaymentResult(...);
}
}
}
Now I have a need to use the behavior in all 3 of these classes into one unit-of-work, I still need the 3 other classes to exist for other dependecies in the project.
My first thought would be to extract a class for each one of the 3 services which takes a unit-of-work as an argument.
Extraction of behavior from current classes
public class PersonCreator
{
public CreatePersonResult CreatePerson(
IUnitOfWork unitOfWork,
CreatePersonParams createPerson)
{
// [code]
}
}
public class PersonService : IPersonService
{
private readonly PersonCreator Creator = new PersonCreator();
public PersonServiceResult CreatePerson(CreatePersonParams createPersonParams)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
var result = Creator.CreatePerson(unitOfWork, createPersonParams);
unitOfWork.Commit();
return new PersonServiceResult(result);
}
}
}
Proposed new class using extracted behavior
public class QuickOrderService : IQuickOrderService
{
private readonly PersonCreator PersonCreator = new PersonCreator();
private readonly OrderCreator OrderCreator = new OrderCreator();
private readonly PaymentProcessor PaymentProcessor = new PaymentProcessor();
public QuickOrderResult CreateQuickOrder(
CreatePersonParams createPersonParams,
IEnumerable<PurchaseItem> items,
CreditCard creditCard)
{
using (var unitOfWork = _unitOfWorkFactory.Create())
{
var person = PersonCreator.CreatePerson(unitOfWork, createPersonParams);
var order = OrderCreator.CreateOrder(unitOfWork, person.Id, items);
var payment = PaymentProcessor.Process(unitOfWork, order.Id, creditCard);
unitOfWork.Commit();
return QuickOrderResult(...);
}
}
}
This works fine, but I am concerned about testing this new class.
Questions about proposal
- Duplicate the majority of the tests for the
QuickOrderService
class - Do not test this class as the majority of it is covered by other tests
- Inject
PersonCreator
,OrderCreator
, andPaymentProcessor
intoQuickOrderService
instead of instanciating them and just test thatQuickOrderService
calls the dependencies correctly
Though when doing this whole excersise it makes me think there may be a better solution that reduces duplication while retains code coverage.