• [spring源码学习]单元测试演化


    1、使用main方法
      最早的测试方法一般是在类中增加main方法,然后在main方法中增加对每个方法的测试代码,如果要测其中一个,就屏蔽掉其他的测试代码,执行后,根据log的打印来判断测试是否成功
    2、使用junit
      junit的出现,使得针对每个方法的单独测试成为可能,在junit中一般使用4.0后,基于注解,在@befor中初始化数据,在@after中恢复测试现场,然后@test注解标注每个测试案例,在测试案例中使用assert断言来判断测试是否成功,使用junit的好处是:
      1)、可以针对每个测试案例编写测试代码
      2)、可以仅运行指定测试案例或者批量运行所有测试案例
      3)、可以使用断言判断测试结果
      4)、必要时候可以提供测试报告
      但同时,在使用junit之后,仍然有许多问题需要解决
      1)对于百分之50以上的应用都是基于spring进行构建,在初始化@befor中我们需要加载spring的bean,意味着多个方法同时测试时候,spring容器被多次初始化
      2)需要硬编码手工获取bean
      3)数据库现场会被破坏,如果在测试方法中执行了数据库改写语句,我们不得不在随后的代码中还原现场,否则数据会被破坏
      4)不方便对数据库操作结果进行验证
    3、使用spring-test框架
      使用junit之后残留的问题,如果我们整个框架使用spring,可以使用spring提供的测试框架spring-test进行解决,以下是一个spring-test的基本案例
    @RunWith(SpringJUnit4ClassRunner.class) //指定测试用例的运行器 这里是指定了Junit4    
    @ContextConfiguration("classpath:applicationContext.xml")    
    @TransactionConfiguration(transactionManager="transactionManager", defaultRollback=true)    
    @Transactional      
    public class TestUserDao {  
        @Autowired  
        private BaseDao<User, Long> userDao = null;  
      
        @Test  
        @Rollback(true)//上面已经设置defaultRollback=true。这里其实可以不用写了  
        public void testModifyUser() {  
            User user = userDao.findById(2L);  
            System.out.println(user.getId());  
            user.setDisplayName("系统管理员4");  
            userDao.saveOrUpdate(user);  
            Assert.assertEquals(userDao.findById(2L).getDisplayName(), "系统管理员4");  
        }  
    }

    我们可以看到一些spring-test的基本操作:

      1)使用RunWith指定使用spring-test来进行单元测试
      2)ContextConfiguration来确定从配置文件或者java文件读取bean,如果是配置文件:@ContextConfiguration("classpath:applicationContext.xml"),如果是从java类开始:@ContextConfiguration(classes = BaseSpringTest.class)
      3)对于从java类开始,我们需要从包扫描,获取所有注解,需要配置@ComponentScan("包名")
      4)在类上TransactionConfiguration配置测试的默认配置,如是否需要使用事物,回滚等
      5)基本类的注解与之前spirng的开发一致
      6)对于单个案例的测试和回滚,默认使用@Rollback和@Transactional进行标记
    4、使用mock框架
      在测试过程中,不可避免的遇到比如我们要测试一个serivce,但是测试过程中会调用到dao层,而dao层需要访问数据库,或者需要引用到网络访问层,所有测试会影响到数据库或者依赖于外部网络环境,所以在测试过程中要求,对系统环境要求很高,这个时候,我们可以使用Mockito框架,进行模拟dao层或者网络访问层进行测试,如下实例:
    public class SimpleTest {  
              
        @Test  
        public void simpleTest(){  
              
            //创建mock对象,参数可以是类,也可以是接口  
            List<String> list = mock(List.class);  
              
            //设置方法的预期返回值  
            when(list.get(0)).thenReturn("helloworld");  
          
            String result = list.get(0);  
              
            //验证方法调用(是否调用了get(0))  
            verify(list).get(0);  
              
            //junit测试  
            Assert.assertEquals("helloworld", result);  
        }  
    } 

      我们使用mock方法模拟了一个list,并将他的get(0)方法设定返回为"helloworld",如果有调用此方法时候,就会返回指定的调用值

      spring-test与mock结合的测试案例写法

    public class MockSpringTest extends BaseSpringTest {  
      
        @Autowired  
        private OrderBefore orderBefore;  
      
        @InjectMocks  
        private OrderCreate orderCreate = mock(OrderCreate.class);  
      
        @Mock  
        private OrderHelper orderHelper;  
    
        @Autowired  
        private OrderStart orderStart;  
        
      
        @Before  
        public void initMocks() throws Exception {  
            MockitoAnnotations.initMocks(this);  //对注解中的mock进行初始化
            ReflectionTestUtils.setField(AopTargetUtils.getTarget(orderStart), "orderCreate", orderCreate);  //AopTargetUtils为自定义的类,将属性注入到bean的方法内
            doReturn(11).when(orderCreate).getAmt();  //定义方法默认返回
            doReturn("success").when(orderHelper).resolve();   //定义方法默认返回
            doCallRealMethod().when(orderCreate).create();   //定义方法调用真实方法
        }  
      
        @Test  
        public void create() {  
            System.out.println("start mock...");  
            //orderStart中注入了orderStart,orderStart中注入了orderCreate,
            //如果按照正常写法,会调用orderCreate的getAmt方法,但是我们之前使用了setFiled将方法将orderStart的属性替换为了mock类,所以可以看到执行结果为11
            orderBefore.before();
        }  
    }  
     
  • 相关阅读:
    Linux下卸载mysql
    ORA-12504: TNS:listener was not given the SERVICE_NAME in CONNECT_DATA
    Centos系统创建用户oracle后,用该用户登陆系统,页面加载报错GConf error
    Java Web 深入分析(6) Tomcat
    CSS 类选择器
    myeclipse 破解
    Java Web 深入分析(5) Java ClassLoader 工作机制
    JFinal(2)JFinal 学习资料
    JFinal(1)JFinal helloworld
    Java Web 深入分析(4) Java IO 深入分析
  • 原文地址:https://www.cnblogs.com/jyyzzjl/p/6182594.html
Copyright © 2020-2023  润新知