一、先说一个结论:单元测试与主项目的spring容器是隔离的,也就是说,单元测试无法访问主项目spring容器,需要自己加载spring容器。
接下来是代码实例,WEB主项目出于运行状态,单元测试中可能会看到如下这样的代码:
代码一:当前类加载式
public class TestSpring { @Test public void testSpring(){ LoginService loginService = this.getBean("loginService"); }
代码二:继承加载式
/** * @Description: 登录单元测试类 */ public class LoginTest extends SpringJunitSupport{ @Autowired private LoginService loginService; @Test public void testLogin(){ loginService.login(); }
代码三:动态添加spring配置文件式
/** * @Description: 登录单元测试类 */ public class LoginTest{
public class TestSpringContextSupport {
如上面三种方式,有一个共同点,就是在单元测试方法执行前,都大费周章的去加载了spring容器。 web主项目出于运行状态,单元测试为什么还要单独加载spring容器,因为web主项目的spring容器对单元测试是隔离的,通过如下手段验证:
验证1:
把单元测试所有加载spring容器的代码去掉,保证主项目出于运行状态,通过@Autowired注解(@Autowired注解可以装配spring内部bean),获取spring应用上下文的bean,然后再通过其获取业务bean,代码如下:
/** * @Description: 登录单元测试类 */ public class LoginTest{
结果一定是空指针异常,context对象为null。
验证二,把web主项目停掉,单元测试使用上面第二种继承的方式加载spring容器,其它同上,代码如下:
/** * @Description: 登录单元测试类,继承SpringJunitSupport加载spring容器 */ public class LoginTest extends SpringJunitSupport{
@RunWith(SpringJUnit4ClassRunner.class)
结果一切正常,如此就验证了单元测试与主项目的spring容器是隔离的,单元测试必须自己加载spring容器。
上面一直在说加载spring容器,其实就是加载配置文件,把配置文件里面的bean加载到spring容器中,上面的验证也一直通过在spring容器中搜索bean对象进行的,理解并应用这一点是非常重要的。
最后的彩蛋,理解是因为项目中有困惑,探究之后才能领悟透彻,比如一个实例:
1、主项目运行,提供服务接口,采用的方式为dubbo+zookeeper方式;
2、单元测试,调用提供者提供的服务,采用继承式加载spring配置文件;
3、抛出异常:地址已经被绑定使用(Address already in use: bind)
java.lang.IllegalStateException: Failed to load ApplicationContext ...... Caused by: com.alibaba.dubbo.rpc.RpcException: Fail to start server(url: dubbo:
4、异常原因:因为采用的是dubbo+zookeeper方式,主项目spring提供者注册了127.0.0.1:20880,单元测试加载spring配置文件想要注册0.0.0.0:20880地址,但是20880已经被主容器占用,所以单元测试无法正常加载。
5、解决办法:将主容器停掉,单独使用单元测试,即作为服务端又作为客户端
6、再次抛出异常:
DEBUG [2016-08-18 18:30:26,603] - ZkClient.java () - Closing ZkClient... INFO [2016-08-18 18:30:26,603] - ZkEventThread.java () - Terminate ZkClient event thread. DEBUG [2016-08-18 18:30:26,603] - ZkConnection.java () - Closing ZooKeeper connected to 119.254.166.167:2181 DEBUG [2016-08-18 18:30:26,603] - ZooKeeper.java () - Closing session: 0x15678a538f900ef DEBUG [2016-08-18 18:30:26,603] - ClientCnxn.java () - Closing client for session: 0x15678a538f900ef ...... DEBUG [2016-08-18 18:30:26,808] - ZkClient.java () - Closing ZkClient...done INFO [2016-08-18 18:30:26,810] - DubboProtocol.java () - [DUBBO] Close dubbo server: /127.0.0.1:20880, dubbo version: 2.5.4, current host: 127.0.0.1 INFO [2016-08-18 18:30:26,812] - AbstractServer.java () - [DUBBO] Close NettyServer bind /0.0.0.0:20880, export /127.0.0.1:20880, dubbo version: 2.5.4, current host: 127.0.0.1 INFO [2016-08-18 18:30:26,812] - ClientCnxn.java () - EventThread shut down for session: 0x15678a538f900ef ERROR [2016-08-18 18:30:26,813] - FailbackRegistry.java () - [DUBBO] Failed to uregister dubbo://127.0.0.1:20880/...... com.alibaba.dubbo.rpc.RpcException: Failed to unregister dubbo://127.0.0.1:20880/业务方法...... at com.alibaba.dubbo.registry.zookeeper.ZookeeperRegistry.doUnregister(ZookeeperRegistry.java:108) at com.alibaba.dubbo.registry.support.FailbackRegistry.unregister(FailbackRegistry.java:160) at com.alibaba.dubbo.registry.integration.RegistryProtocol$1.unexport(RegistryProtocol.java:130) at com.alibaba.dubbo.config.ServiceConfig.unexport(ServiceConfig.java:270) at com.alibaba.dubbo.config.spring.ServiceBean.destroy(ServiceBean.java:255) at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:258) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:538) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:514) at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:831) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:483) at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:923) at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:897) at org.springframework.context.support.AbstractApplicationContext$1.run(AbstractApplicationContext.java:811) Caused by: java.lang.NullPointerException at org.I0Itec.zkclient.ZkClient$8.call(ZkClient.java:720) at org.I0Itec.zkclient.ZkClient.retryUntilConnected(ZkClient.java:675) at org.I0Itec.zkclient
|