В Castle Windsor 3 переопределите существующую регистрацию компонентов в модульном тесте. - PullRequest
26 голосов
/ 13 февраля 2012

Я пытаюсь использовать Castle Windsor в своих автоматических тестах, например:

По каждому тесту:

  • Функция Setup() создает контейнер Windsor, регистрируя реализации по умолчанию для каждого компонента
  • Функция Test обращается к компонентам по методу IWindsorContainer.Resolve<T> и проверяет их поведение
  • Функция TearDown() удаляет контейнер Windsor (и любые созданные компоненты)

Например, у меня может быть 15 тестов, которые обращаются к компонентам, что косвенно приводит к созданию IMediaPlayerProxyFactory компонента. Функция SetUp регистрирует достаточно хорошую реализацию IMediaPlayerProxyFactory, поэтому у меня нет бремени обслуживания для регистрации этого в каждом из 15 тестов.

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

this.WindsorContainer.Register(
                                 Component.For<IMediaPlayerProxyFactory>()
                                          .Instance(mockMediaPlayerProxyFactory)
                              );

Но Виндзор выдает Castle.MicroKernel.ComponentRegistrationException с сообщением «Компонент с таким именем уже существует».

Есть ли способ сделать мой mockMediaPlayerProxyFactory экземпляром по умолчанию для IMediaPlayerProxyFactory, отбрасывая уже зарегистрированный компонент?

<ч /> Согласно документации , Castle Windsor 3 допускает переопределения регистрации, но я мог найти только один пример:

Container.Register(
    Classes.FromThisAssembly()
        .BasedOn<IEmptyService>()
        .WithService.Base()
        .ConfigureFor<EmptyServiceA>(c => c.IsDefault()));

ConfigureFor - метод класса BasedOnDescriptor. В моем случае я не использую FromDescriptor или BasedOnDescriptor.

Ответы [ 2 ]

63 голосов
/ 13 февраля 2012

Есть две вещи, которые вы должны сделать, чтобы создать переопределяющий экземпляр:

  1. Присвойте ему уникальное имя
  2. вызов метода IsDefault

Итак, чтобы пример работал:

this.WindsorContainer.Register(
                             Component.For<IMediaPlayerProxyFactory>()
                                      .Instance(mockMediaPlayerProxyFactory)
                                      .IsDefault()
                                      .Named("OverridingFactory")
                          );

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

public static class TestWindsorExtensions
{
    public static ComponentRegistration<T> OverridesExistingRegistration<T>(this ComponentRegistration<T> componentRegistration) where T : class
    {
        return componentRegistration
                            .Named(Guid.NewGuid().ToString())
                            .IsDefault();
    }
}

Теперь пример можно упростить до:

this.WindsorContainer.Register(
                             Component.For<IMediaPlayerProxyFactory>()
                                      .Instance(mockMediaPlayerProxyFactory)
                                      .OverridesExistingRegistration()
                          );

<ч /> Позже Редактировать

В версии 3.1 представлен метод IsFallback. Если я зарегистрирую все свои начальные компоненты с помощью IsFallback, то любые новые регистрации будут автоматически отменять эти первоначальные регистрации. Я бы пошел по этому пути, если бы функциональность была доступна в то время.

https://github.com/castleproject/Windsor/blob/master/docs/whats-new-3.1.md#fallback-components

1 голос
/ 13 февраля 2012

Не используйте свой контейнер в тестах. Вместо этого установите null в TearDown() и повторно инициализируйте его для каждого фактического теста.

...