Использование Factory для замены экземпляров подделками из Isolation Framework

StackOverflow https://stackoverflow.com/questions/2328193

Вопрос

Месяц назад я закончил читать книгу «Искусство модульного тестирования», и сегодня у меня наконец-то появилось время начать использовать Rhino Mocks для модульного тестирования — сервиса, который отправляет/получает сообщения на устройства (UDP) и сохраняет/загружает данные из базы данных.
Конечно, я хочу изолировать базу данных и связь UDP.

Например, для доступа к базе данных у нас есть несколько классов со статическими методами, назовем их:

  • ОбластьADBAAccess
  • ОбластьBDBAAccess
  • ОбластьCDBAAccess

Эти классы имели статические методы, которые выполняли доступ к базе данных.
Чтобы иметь возможность их заглушить, я сделал их методы общедоступными и виртуальными.

Затем я начал рефакторинг кода, чтобы иметь возможность заменять экземпляры этих классов в коде.
Попробовав разные вещи, я в итоге получил фабричный класс, который, кажется, упрощает задачу.

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-х местах кажется бесполезным.
Спасибо!

Это было полезно?

Решение

Вероятно, вы могли бы использовать контейнеры IoC, такие как Windsor, StructureMap или Ninject, которые значительно облегчили бы вашу жизнь, и фактически они также работают как «фабрика», созданная вами вручную, но они гораздо более мощные.

Также существуют автоматические контейнеры, которые автоматически создают макетные зависимости для ваших классов, чтобы вы могли сохранить дополнительные строки кода и сделать ваш тест менее хрупким.

Что касается вопроса о необходимости интерфейса вместо классов, то это, по сути, принцип инверсии зависимостей, который гласит, что модули (классы) более высокого уровня не должны зависеть от модулей (классов) более низкого уровня, оба они должны зависеть от абстракций.Интерфейсы — это абстракции.Я предлагаю вам взглянуть на принципы S.O.L.I.D, которые сделают вашу жизнь намного проще, по крайней мере, они сделали это со мной.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top