Sometimes you are not able to use Extract Interface refactoring because interface of parameter may be too large or there may be no interface at all. You just have class to pass in and you are not able to fake it or extend it to get class testable. In this case you have to use Adapt Parameter refactoring to create adapter that is seen through common some common class of interface.
Let’s look at the following code.
public class CustomerCardService
{
//...
public bool IsValidCustomer(MagneticStripeCardReader reader)
{
var customerCode = reader.ReadCustomerCode();
var expiryDate = reader.ReadExpiryDate();
var customer = _repository.GetByCode(customerCode);
if (customer == null)
return false;
return (expiryDate > DateTime.Now);
}
// ...
}
Here we can see a method that accepts class MagneticStripeCardReader. This class implements no interfaces and we are not able to extend it. We cannot fake it and we cannot go to interfaces. To get over this problem let’s create interface that we can use to make this method testable.
public interface ICustomerDataReader
{
string ReadCustomerCode();
DateTime ReadExpiryDate();
}
As a next thing we have to modify this method to make it accept our new interface. All we have to do is to change parameter signature.
public bool IsValidCustomer(ICustomerDataReader reader)
{
// ...
}
After that let’s write fake class we can use to test this method.
public class FakeCardReaderSource : ICustomerDataReader
{
private string _customerCode;
private DateTime _expiryDate;
public FakeCardReader(string customerCode, DateTime expiryDate)
{
_customerCode = customerCode;
_expiryDate = expiryDate;
}
public string ReadCustomerCode()
{
return _customerCode;
}
public DateTime ReadExpiryDate()
{
return _expiryDate;
}
}
Now we are almost finished. All we need to do is to write adapter class for MagneticStripeCardReader.
public class MagneticStripeSource : ICustomerDataReader
{
private MagneticStripeCardReader _reader;
public MagneticStripeSource(MagneticStripeCardReader reader)
{
_reader = reader;
}
public string ReadCustomerCode()
{
return _reader.ReadCustomerCode();
}
public DateTime ReadExpiryDate()
{
return _reader.ReadExpiryDate();
}
}
Besides testability we achieved one thing more – we can easily create adapters for other types of card reader classes (by example, we may have SmartCardReader in the future). In current case we were happy – we had made no modifications to original method body. But in real world we usually have to modify also method body.