Spring beans redefinition in unit test environment

2019-01-16 04:07发布

we are using Spring for my application purposes, and Spring Testing framework for unit tests. We have a small problem though: the application code loads a Spring application context from a list of locations (xml files) in the classpath. But when we run our unit tests, we want some of the Spring beans to be mocks instead of full-fledged implementation classes. Moreover, for some unit tests we want some beans to become mocks, while for other unit tests we want other beans to become mocks, as we are testing different layers of the application.

All this means I want to redefine specific beans of the application context and refresh the context when desired. While doing this, I want to redefine only a small portion of the beans located in one (or several) original xml beans definition file. I cannot find an easy way to do it. It's always regarded that Spring is a unit testing friendly framework so I must be missing something here.

Do you have any ideas how to do it?

Thanks.

13条回答
不美不萌又怎样
2楼-- · 2019-01-16 04:08

You do not need to use any test contexts (doesn't matter is XML or Java based). Since Spring boot 1.4 there is available new annotation @MockBean which introduced native support for mocking and Spying of Spring Beans.

查看更多
混吃等死
3楼-- · 2019-01-16 04:16

You can use the import feature in your test app context to load in the prod beans and override the ones you want. For example, my prod data source is usually acquired via JNDI lookup, but when I test I use a DriverManager data source so I don't have to start the app server to test.

查看更多
Emotional °昔
4楼-- · 2019-01-16 04:17

I want to do the same thing, and we're finding it essential.

The current mechanism we use is fairly manual but it works.

Say for instance, you wish to mock out bean of type Y. What we do is every bean that has that dependency we make implement an interface - "IHasY". This interface is

interface IHasY {
   public void setY(Y y);
}

Then in our test we call the util method...

 public static void insertMock(Y y) {
        Map invokers = BeanFactory.getInstance().getFactory("core").getBeansOfType(IHasY.class);
        for (Iterator iterator = invokers.values().iterator(); iterator.hasNext();) {
            IHasY invoker = (IHasY) iterator.next();
            invoker.setY(y);
        }
    }

I do not want to create a whole xml file just to inject this new dependency and that is why I like this.

If you're willing to create an xml config file then the way to go would be to create a new factory with the mock beans and make your default factory a parent of this factory. Make sure then that you load all your beans from the new child factory. When doing this the sub-factory will override the beans in the parent factory when the bean id's are the same.

Now if, in my test, If I could programmatically create a factory, that would be awesome. Having to use xml is just too cumbersome. I'm looking to create that child factory with code. Then each test can configure its factory the way it wants. There's no reason why a factory like that won't work.

查看更多
The star\"
5楼-- · 2019-01-16 04:22

Perhaps you could use qualifiers for your beans? You would redefine the beans you want to mock up in a separate application context and label them with a qualifier "test". In your unit tests, when wiring your beans always specify the qualifier "test" to use the mock ups.

查看更多
等我变得足够好
6楼-- · 2019-01-16 04:25

Easy. You use a custom application context for your unit tests. Or you don't use one at all and you manually create and inject your beans.

It sounds to me like your testing might be a bit too broad. Unit testing is about testing, well, units. A Spring bean is a pretty good example of a unit. You shouldn't need an entire application context for that. I find that if your unit testing is so high level that you need hundreds of beans, database connections, etc then you have a really fragile unit test that is going to break on the very next change, will be hard to maintain and really isn't adding a lot of value.

查看更多
太酷不给撩
7楼-- · 2019-01-16 04:26

spring-reinject is designed to substitute beans with mocks.

查看更多
登录 后发表回答