I'm performing a business logic but the way I have implemented it, looks a bit convoluted and makes unit testing harder. How do I break down this logic into easier unit-testable tiny methods?
public async Task<ResultTypes> ValidatePinAsync(int id, string pin)
{
ICustomer customer = await _repository.GetCustomer(id);
if (customer.PinDisabled)
return ResultTypes.PinDisabled;
if (string.IsNullOrEmpty(customer.PinNumber))
{
customer.PinNumber = customer.DoB.ToString();
//perform repository call to update PIN here?
if (customer.PinNumber == pin)
{
return ResultTypes.Success;
}
else
{
//perform repository call to update failure count and then return disabled or invalid
return ResultTypes.InvalidPinEntered;
}
}
if (customer.PinNumber == pin)
{
return ResultTypes.Success;
}
else
{
//perform repository call to update failure count and then return disabled or invalid
}
return ResultTypes.Success;
}
I refactored your code a little (as per @canton7's suggestion) to leaf only 3 if statements, none of wich are nested. The logic inside the if (string.IsNullOrEmpty(customer.PinNumber))
could be moved to it's own method.
public async Task<ResultTypes> ValidatePinAsync(int id, string pin)
{
ICustomer customer = await _repository.GetCustomer(id);
if (customer.PinDisabled)
return ResultTypes.PinDisabled;
if (string.IsNullOrEmpty(customer.PinNumber))
{
customer.PinNumber = customer.DoB.ToString();
//perform repository call to update PIN here?
}
if (customer.PinNumber != pin)
{
//perform repository call to update failure count and then return disabled or invalid
return ResultTypes.InvalidPinEntered
}
return ResultTypes.Success;
}