• 理一理Spring如何对接JUnit


    测试代码

    package org.simonme.srcstudy.spring3.demo.stub;
    
    import static org.junit.Assert.assertNotNull;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.simonme.srcstudy.spring3.demo.service.UserService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
    
    /**
     * <一句话功能简述>
     * <功能详细描述>
     * 
     * @author  http://www.cnblogs.com/simoncook
     * @version  [版本号, 2017年11月4日]
     * @see  [相关类/方法]
     * @since  [产品/模块版本]
     */
    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations={"/applicationContext.xml"})
    public class UserServiceAssemblyByJUnit
    {
        
        
        private UserService userService;
    
        @Test
        public void test()
        {
            assertNotNull(userService);
        }
    
        public UserService getUserService()
        {
            return userService;
        }
    
        @Autowired
        public void setUserService(UserService userService)
        {
            this.userService = userService;
        }
    
    

    分析方式

    this.userService = userService; 这一行直接断点

    堆栈信息

    org.simonme.srcstudy.spring3.demo.stub.UserServiceAssemblyByJUnit.setUserService(org.simonme.srcstudy.spring3.demo.service.UserService) line: 50	
    sun.reflect.NativeMethodAccessorImpl.invoke0(java.lang.reflect.Method, java.lang.Object, java.lang.Object[]) line: not available [native method]	
    sun.reflect.NativeMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 39	
    sun.reflect.DelegatingMethodAccessorImpl.invoke(java.lang.Object, java.lang.Object[]) line: 25	
    java.lang.reflect.Method.invoke(java.lang.Object, java.lang.Object...) line: 597	
    org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(java.lang.Object, java.lang.String, org.springframework.beans.PropertyValues) line: 582	
    org.springframework.beans.factory.annotation.InjectionMetadata.inject(java.lang.Object, java.lang.String, org.springframework.beans.PropertyValues) line: 84	
    org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(org.springframework.beans.PropertyValues, java.beans.PropertyDescriptor[], java.lang.Object, java.lang.String) line: 282	
    org.springframework.beans.factory.support.DefaultListableBeanFactory(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory).populateBean(java.lang.String, org.springframework.beans.factory.support.AbstractBeanDefinition, org.springframework.beans.BeanWrapper) line: 1074	
    org.springframework.beans.factory.support.DefaultListableBeanFactory(org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory).autowireBeanProperties(java.lang.Object, int, boolean) line: 374	
    org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(org.springframework.test.context.TestContext) line: 110	
    org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(org.springframework.test.context.TestContext) line: 75	
    org.springframework.test.context.TestContextManager.prepareTestInstance(java.lang.Object) line: 321	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest() line: 220	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall() line: 301	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1(org.junit.internal.runners.model.ReflectiveCallable).run() line: 12	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(org.junit.runners.model.FrameworkMethod) line: 303	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(org.junit.runners.model.FrameworkMethod, org.junit.runner.notification.RunNotifier) line: 240	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner(org.junit.runners.BlockJUnit4ClassRunner).runChild(java.lang.Object, org.junit.runner.notification.RunNotifier) line: 50	
    org.junit.runners.ParentRunner$3.run() line: 238	
    org.junit.runners.ParentRunner$1.schedule(java.lang.Runnable) line: 63	
    org.springframework.test.context.junit4.SpringJUnit4ClassRunner(org.junit.runners.ParentRunner<T>).runChildren(org.junit.runner.notification.RunNotifier) line: 236	
    org.junit.runners.ParentRunner<T>.access$000(org.junit.runners.ParentRunner, org.junit.runner.notification.RunNotifier) line: 53	
    org.junit.runners.ParentRunner$2.evaluate() line: 229	
    
    

    看junit的运作方式

    从main方法到runner

    翻看官方guide 很容易发现JUnitCore是main方法所在类
    JUnitCore是如何到runner的呢? 看下面分析

    org.junit.runner.JUnitCore.main(String...)
    // 一些listener构造之类,然后通过AllDefaultPossibilitiesBuilder 构建runner  
    org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(Class<?>)
    List<RunnerBuilder> builders = Arrays.asList(
                    ignoredBuilder(),
                    annotatedBuilder(),
                    suiteMethodBuilder(),
                    junit3Builder(),
                    junit4Builder());
    
            for (RunnerBuilder each : builders) {
                Runner runner = each.safeRunnerForClass(testClass);
                if (runner != null) {
                    return runner;
                }
            }
    

    找到一个就直接返回
    ignoredBuilder 可以用过Ignore注解忽略你的test case
    annotatedBuilder 是找 RunWith注解定义的自定义runner
    junit3Builder 如果test case 继承自TestCase类 则用junit3的runner
    junit4Builder 直接对接 BlockJUnit4ClassRunner
    spring的SpringJUnit4ClassRunner也是继承自BlockJUnit4ClassRunner

    回头去看上面的堆栈信息 一目了然
    关键点在于重写 org.junit.runners.BlockJUnit4ClassRunner.createTest() 这个方法

    protected Object createTest() throws Exception {
            return getTestClass().getOnlyConstructor().newInstance();
        }
    
    /**
    	 * Delegates to the parent implementation for creating the test instance and
    	 * then allows the {@link #getTestContextManager() TestContextManager} to
    	 * prepare the test instance before returning it.
    	 * 
    	 * @see TestContextManager#prepareTestInstance(Object)
    	 */
    	@Override
    	protected Object createTest() throws Exception {
    		Object testInstance = super.createTest();
    		getTestContextManager().prepareTestInstance(testInstance);
    		return testInstance;
    	}
    

    也就是把JUnit原生的创建test case的instance的过程接用spring容器装配的方式接管过来就可以了。

  • 相关阅读:
    Redis
    IDEA编码相关,解决yml编码错误导致的 java.nio.charset.MalformedInputException: Input length = 1
    文件上传和下载
    SpringBoot+Mybatis+Postman实现增删改查
    多态与反射
    正则表达式
    原码、反码、补码的用法和理解
    @Conditional & @Profile SpringBoot中自动化配置条件注解。
    Spring Boot 中的 Starter
    第一个项目~千寻在线水果商城
  • 原文地址:https://www.cnblogs.com/simoncook/p/7784689.html
Copyright © 2020-2023  润新知