Месяц назад я закончил читать книгу «Искусство модульного тестирования», и сегодня у меня наконец-то появилось время начать использовать Rhino Mocks с модульным тестированием службы, которая отправляет / получает сообщения на устройства (UDP) и сохраняет / загружает данные из базы данных.
Конечно, я хочу изолировать базу данных и связь UDP.
Например, для доступа к базе данных у нас есть несколько классов со статическими методами, давайте их назовем:
- AreaADBAccess
- AreaBDBAccess
- AreaCDBAccess
Эти классы имели статические методы, которые выполняли доступ к базе данных.
Чтобы иметь возможность заглушить их, я сделал их методы общедоступными виртуальными.
Затем я начал рефакторинг кода, чтобы иметь возможность заменить экземпляр этих классов в коде.
Попробовав разные вещи, я получил фабричный класс, который, кажется, делает все так просто.
public class ObjectFactory
{
private static Dictionary<Type, object> Instances = new Dictionary<Type, object>();
public static T GetInstance<T>() where T : new()
{
if(Instances.ContainsKey(typeof(T)))
return (T)Instances[typeof(T)];
return new T();
}
public static void SetInstance<T>(object obj)
{
Instances[typeof(T)] = obj;
}
}
Тогда по коду я могу использовать
private AreaADBAccess DBAccess = ObjectFactory.GetInstance<AreaADBAccess>();
А по методу теста я делаю что-то вроде
AreaADBAccess dbAccess = mocks.Stub<AreaADBAccess>();
using (mocks.Record())
{
...
}
ObjectFactory.SetInstance<AreaADBAccess>(dbAccess);
//Invoke the test method
...
Это первое решение, и я понимаю, что оно может быть сделано лучше.
Можете ли вы прокомментировать это и указать мне лучшие практики?
Можете ли вы также объяснить мне, почему я хотел бы иметь интерфейс вместо определения методов как виртуальных? Кажется бесполезным повторять заголовки метода в 2 местах.
Спасибо!