Изменение только одной из зависимостей в большом графе зависимостей в контейнере ioc для целей тестирования - PullRequest
2 голосов
/ 23 марта 2012

Это корень композиции моего приложения:

    MutablePicoContainer container = new DefaultPicoContainer();
    container.addComponent(LDAPManager.class);
    container.addComponent(LoginDelayer.class);
    container.addComponent(CommandFactory.class);
    container.addComponent(FileSystem.class);
    container.addComponent(ProtocolFactory.class);
    container.addComponent(new TemporaryFolder(container.getComponent(FileSystem.class), new File("abc")));
    container.addComponent(ConnectedClientFactory.class);
    container.addComponent(Server.class);

    Server server = container.getComponent(Server.class);

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

container.addComponent(new TemporaryFolder(container.getComponent(FileSystem.class), new File("def")));

и позволить контейнеру понять, что я хочу заменить исходный экземпляр TemporaryFolder на новый.Есть ли встроенные средства для этого в пико-контейнере (или других облегченных контейнерах Java)?Если нет, то каков стандартный подход к решению этой проблемы?

Спасибо

Ответы [ 4 ]

1 голос
/ 25 марта 2012

Основываясь на ответе Бронумского, я сделал простой хак-класс, который , кажется, работает для моих целей. Atm:

import org.picocontainer.DefaultPicoContainer;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.injectors.AbstractInjector.UnsatisfiableDependenciesException;

public class IoCContainer {
    private final MutablePicoContainer container = new DefaultPicoContainer();

    public void addComponent(Object component) {
        if (containsComponent(component.getClass()))
            container.removeComponent(component.getClass());

        container.addComponent(component.getClass(), component);
    }

    public void addComponent(Class<?> key, Object component) {
        if (containsComponent(key))
            container.removeComponent(key);

        container.addComponent(key, component);
    }

    public void addComponent(Class<?> key, Class<?> component) {
        if (containsComponent(key))
            container.removeComponent(key);

        container.addComponent(key, component);
    }

    public void addComponent(Class<?> component) {
        if (containsComponent(component))
            container.removeComponent(component);

        container.addComponent(component);
    }

    public boolean containsComponent(Class<?> component) {
        try {
            container.getComponent(component);
        } catch (UnsatisfiableDependenciesException e) {
            return false;
        }
        return true;
    }

    public <T> T getComponent(Class<T> component) {
        T result = container.getComponent(component);
        if (result == null)
            throw new NoComponentFoundException();

        return result;
    }
}
1 голос
/ 23 марта 2012

Возможно, это специфическая среда IoC, но мы делаем это в Виндзоре с помощью .net для нашего приемочного тестирования.Каждый из наших сервисов подключает свой собственный контейнер со всеми необходимыми компонентами.

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

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

0 голосов
/ 15 апреля 2012

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

public class Service {
    private String data;

    public Service(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public static void main(String[] args) {
        MutablePicoContainer container = new DefaultPicoContainer();
        container.as(Characteristics.USE_NAMES).addComponent(Service.class);
        container.addComponent("Real Data");
        // below line added only in test for injecting test data ...
        container.addComponent("data", "Mock Data"); 
        System.out.println(container.getComponent(Service.class).getData());
    }
}

, и это печатает Mock Data, если присутствует строка «Mock Data», и Real Data, если она закомментирована.Это работает, потому что «данные» - это имя параметра.

0 голосов
/ 08 апреля 2012

На самом деле это очень просто. Обратите внимание на это предостережение от Javadoc для addComponent(java.lang.Object)

Зарегистрировать произвольный объект. Класс объекта будет использоваться как ключ. Вызов этого метода эквивалентен вызову addComponent(componentImplementation, componentImplementation).

(Акцент мой.)

Вы также можете установить ключ явно, используя addComponent(java.lang.Object, java.lang.Object, org.picocontainer.Parameter...), если хотите.

Основываясь на дополнительной информации, это поведение приведет к конфликту клавиш, когда два члена одного класса указаны для прежнего интерфейса. Чтобы это исправить, вам понадобится какой-то метод для урегулирования конфликта ... который вы продвинули вперед и предоставил пример рабочего кода для .

Я открыто признаю, что я не использую этот фреймворк для внедрения зависимостей, поэтому, если я здесь неосновный, приношу свои извинения. Я очень рекомендую попробовать Mockito когда-нибудь. Для этих сценариев использовать абсолютно приятно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...