Использование Spring для вставки EasyMock mocks вызывает ClassCastException - PullRequest
3 голосов
/ 28 мая 2009

Я пытаюсь заставить Spring вставлять макеты EasyMock в мои юнит-тесты.

В моем applicationContext.xml у меня есть это:

<bean id="mockService"  class="org.easymock.EasyMock" factory-method="createMock"  name="MockService">
    <constructor-arg index="0" value="my.project.Service"/>
</bean>

В моем модульном тесте у меня есть это:

@Autowired
@Qualifier("mockService")
private Service service;

public void testGetFoo() {
    Foo foo = new Foo();

    expect(service.findFoo()).andReturn(foo);
    replay(service); // <-- This is line 45, which causes the exception

    // Assertions go here...
}

Когда я пытаюсь запустить свой тест, я получаю следующую трассировку стека:

java.lang.ClassCastException: org.springframework.aop.framework.JdkDynamicAopProxy
at org.easymock.EasyMock.getControl(EasyMock.java:1330)
at org.easymock.EasyMock.replay(EasyMock.java:1279)
at TestFooBar.testGetFoo(TestVodServiceLocator.java:45)

Я довольно новичок в Spring и EasyMock, но мне кажется, что ошибка вызвана тем, что EasyMock пытается вызвать метод, который считается экземпляром EasyMock, но на самом деле это динамический прокси, созданный Весна. Насколько я понимаю, динамические прокси реализуют только методы, определенные в интерфейсе, в данном случае это интерфейс для Service.

Что я не понимаю, так это то, что из того, что я прочитал (также здесь ), то, чего я пытаюсь достичь, по крайней мере, представляется возможным.

Итак, мой вопрос: что я не делаю или что я делаю неправильно?

Ответы [ 4 ]

6 голосов
/ 02 июня 2009

Вы также можете создать вспомогательный метод для развертывания прокси EasyMock из прокси Spring для определения ожидаемого поведения:

public static <T> T unwrap(T proxiedInstance) {
  if (proxiedInstance instanceof Advised) {
    return unwrap((T) ((Advised) proxiedInstance).getTargetSource().getTarget());
  }

  return proxiedInstance;
}

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

4 голосов
/ 28 мая 2009

Решено!

Я пропустил это в моем applicationContext.xml:

<bean id="txProxyAutoCreator" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <property name="beanNames">
        <list>

            <value>*Service</value>
            <!--   ^^^^^^^^    
               This is the problem!
            -->
        </list>
    </property>
    <property name="interceptorNames">
        <list>
            <value>txAdvisor</value>
        </list>
    </property>
</bean>

... что заставляет Spring автоматически создавать прокси-объекты для всех bean-компонентов с именами, заканчивающимися на «Service».

Моим решением было явное перечисление бинов вместо использования подстановочных знаков. Однако мне это кажется немного хрупким, поэтому, если кто-нибудь знает, как задать все * Service bean , кроме FooService, я был бы признателен.

1 голос
/ 29 апреля 2014

Я знаю, что этот вопрос старый, но я наткнулся на него в поисках аналогичной проблемы.

Проблема в том, что Spring не знает тип фиктивного объекта. Используемый вами метод выглядит следующим образом:

public static <T> T createMock(final Class<T> toMock) {
    return createControl().createMock(toMock);
}

Spring не достаточно умен, чтобы извлечь T из аргумента конструктора (по крайней мере, в последний раз, когда я проверял), поэтому он думает, что возвращаемый объект имеет тип java.lang.Object. Как следствие, созданный прокси не реализует my.project.Service и поэтому не может быть введен.

Поэтому ответ должен сказать Spring требуемый тип.

1 голос
/ 29 мая 2009

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

Тем не менее, довольно странно, что вы вводите фиктивный боб в класс вообще. У тебя может быть веская причина, но для меня это запах кода. Я бы посоветовал вам рассмотреть только подключение реальных служб к вашим тестовым классам и затем инициализировать фиктивные объекты по мере необходимости. Зачем тратить 3 строки в Java и еще 3 строки в XML (плюс 1 строка для их сброса), чтобы создать фиктивный объект без зависимостей? Просто скажите Service service = (Сервис) createMock (Service.class). Я бы посоветовал создавать их так, как вам нужно, устанавливать ожидания, вводить их, использовать, а затем отбрасывать. В вашей модели вам придется помнить, что каждый раз, когда вы его используете, вы сбрасываете фиктивный объект, что менее понятно, чем просто создание нового.

Конечно, это проблема стиля, а не проблема правильности, поэтому игнорируйте по желанию.

...