EasyMock工厂方法生成的bean的自动装配?

发布于 2024-11-15 02:07:51 字数 2257 浏览 3 评论 0原文

我有一个对我来说似乎很奇怪的问题。我有以下设置:

一个接口:

package com.example;

public interface SomeDependency {
}

一个 spring 组件:

package com.example;

@Component
public class SomeClass {
}

一个带有 EasyMock 生成的模拟 bean 的 spring 测试配置:

<beans ....>
    <context:component-scan base-package="com.example"/>

    <bean id="someInterfaceMock" class="org.easymock.EasyMock" factory-method="createMock">
        <constructor-arg value="com.example.SomeDependency" />
    </bean> 
</beans>

和一个单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testconfig.xml")
public class SomeClassTest {

    @Autowired
    SomeClass someClass;

    @Autowired
    SomeDependency someDependency;

    @Test
    public void testSomeClass() throws Exception {
        assertNotNull(someClass);
    }

    @Test
    public void testSomeDependency() throws Exception {
        assertNotNull(someDependency);
    }
}

项目编译并且测试通过,没有任何问题,即自动装配 SomeClass< /em> (“真实”对象)和 SomeDependency (由 EasyMock 生成的模拟对象)成功。

但是,如果我将 SomeClass 的实现更改为:

@Component
public class SomeClass {

    @Autowired
    SomeDependency someDependency;
}

两个测试都会失败,因为

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.SomeDependency] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

所以我的问题是:

  1. 为什么 Spring 无法将依赖项自动装配到 SomeClass (当它成功自动装配对 SomeClassTest 具有相同的依赖性)?
  2. 如何更改 SomeClassTesttestconfig.xml 以使测试通过?

评论:实际上,SomeClass 表示的类是框架的一部分。因此,它不能轻易更新,至少不能在合理的时间内更新。

依赖项:

  • Spring:3.0.5.RELEASE
  • EasyMock:3.0

编辑:

从 Spring 3.2 RC1 开始,通用工厂方法和模拟对象的问题已经已解决

/马蒂亚斯

I have a problem that seems really strange to me. I have the following setup:

An interface:

package com.example;

public interface SomeDependency {
}

A spring component:

package com.example;

@Component
public class SomeClass {
}

A spring test config with a mocked bean generated by EasyMock:

<beans ....>
    <context:component-scan base-package="com.example"/>

    <bean id="someInterfaceMock" class="org.easymock.EasyMock" factory-method="createMock">
        <constructor-arg value="com.example.SomeDependency" />
    </bean> 
</beans>

And a unit test:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/testconfig.xml")
public class SomeClassTest {

    @Autowired
    SomeClass someClass;

    @Autowired
    SomeDependency someDependency;

    @Test
    public void testSomeClass() throws Exception {
        assertNotNull(someClass);
    }

    @Test
    public void testSomeDependency() throws Exception {
        assertNotNull(someDependency);
    }
}

The project compiles and the tests pass without any problem, i.e. autowiring of both SomeClass (a "real" object) and SomeDependency (a mock object generated by EasyMock) succeed.

However, if I change the implementation of SomeClass to:

@Component
public class SomeClass {

    @Autowired
    SomeDependency someDependency;
}

both tests fail because

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.example.SomeDependency] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

So my questions are:

  1. Why does Spring fail to autowire the dependency to SomeClass (when it succeeds autowiring the same dependency to SomeClassTest)?
  2. How can I change the SomeClassTest or testconfig.xml to make the tests pass?

Comment: In reality the class represented by SomeClass is part of a framework. Consequently, it cannot easily be updated, at least not within reasonable time.

Dependencies:

  • Spring: 3.0.5.RELEASE
  • EasyMock: 3.0

Edit:

As of Spring 3.2 RC1, the problem with generic factory methods and mock objects has been solved.

/Mattias

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

歌入人心 2024-11-22 02:07:51

当使用工厂通过自动装配创建 bean 时,xml 中定义的顺序实际上很重要。如果将 someInterfaceMock 声明放在 component-scan 之上,它将起作用。

一些澄清原因:当 Spring 尝试自动装配 SomeClass 时,它会搜索 SomeDependency 类型的 bean。在此阶段 someInterfaceMock 仍然是一个工厂,因此 Spring 检查工厂方法 EasyMock.createMock(...) 的签名,该方法返回 所以 Spring 只找到一个不是所需类型的 Object

更好的方法是使用 Spring 的 FactoryBean 接口来创建模拟。

这是一个应该可以工作的基本实现:

public class EasyMockFactoryBean<T> implements FactoryBean<T> {
    private Class<T> mockedClass;

    public void setMockedClass(Class mockedClass) {
        this.mockedClass = mockedClass;
    } 

    public T getObject() throws Exception {
        return EasyMock.createMock(mockedClass);
    }

    public Class<T> getObjectType() {
        return mockedClass;
    }

    public boolean isSingleton() {
        return true;
    } 

}

这是 bean 定义(顺序并不重要!):

<bean class="com.example.EasyMockFactoryBean">
    <property name="mockedClass" value="com.example.Dependancy"/>
</bean>    

It seems the order of the definitions in the xml actually matter when using factories to create beans with autowiring. If you place the declaration of someInterfaceMock above component-scan it will work.

Some clarification why: When Spring tries to autowire SomeClass it searches for a bean of type SomeDependency. At this stage someInterfaceMock is still a factory so Spring checks the signature of the factory method EasyMock.createMock(...) which returns <T> so Spring only finds an Object which isn't the type required.

A better way would be to use Spring's FactoryBean interface to create your mocks.

Here is a basic implementation that should work:

public class EasyMockFactoryBean<T> implements FactoryBean<T> {
    private Class<T> mockedClass;

    public void setMockedClass(Class mockedClass) {
        this.mockedClass = mockedClass;
    } 

    public T getObject() throws Exception {
        return EasyMock.createMock(mockedClass);
    }

    public Class<T> getObjectType() {
        return mockedClass;
    }

    public boolean isSingleton() {
        return true;
    } 

}

Here is the bean definition (the order won't matter!):

<bean class="com.example.EasyMockFactoryBean">
    <property name="mockedClass" value="com.example.Dependancy"/>
</bean>    
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文