Spring MVC的单元测试和集成测试(不使用mock)

来源:互联网 发布:c语言三日通pdf下载 编辑:程序博客网 时间:2024/05/22 14:33

文章要点:

1. 为Controller编写测试,不需要应用服务器环境

2. 为Service编写测试,不需要应用服务器环境


Spring为我们提供了一个测试套件Spring-test,与JUnit结合,可以在运行测试时启动IoC容器测试Service,数据库,也可以在脱离web容器的环境下模拟http请求测试Controller,甚是给力。


测试Controller

当我们编写完一个Controller后,常规的测试方式就是部署运行应用,然后观察运行效果。如果想要编写测试,也要用Mock对象模拟请求参数,模拟HttpSession,特别麻烦。现在spring-test为我们提供了一个更加优雅的测试方式。例如,要测试下面的Controller:
[java] view plain copy print?
  1. @RequestMapping(value = {"/""/shop"}, method = RequestMethod.GET)  
  2.     public String home() {  
  3.         return "index";  
  4.     }  

其对应的测试代码为:
[java] view plain copy print?
  1. @Test  
  2.     public void testHome() throws Exception {  
  3.         MockMvc mock = MockMvcBuilders.standaloneSetup(homeController).build();  
  4.   
  5.         mock.perform(get("/")).andExpect(status().isOk())  
  6.                 .andExpect(forwardedUrl("index"));  
  7.           
  8.           
  9.     }  

在测试代码中,我们向 HomeController 发送GET请求 "/", 然后判断(andExpect()方法)HTTP状态码是否为200,再判断是否跳转到了"index"页面。如果有任何一环出错,测试就会失败。
我们也可以传送请求参数:
[java] view plain copy print?
  1. mock.perform(get("/").param("username""password"))  
  2.             .andExpect(status().isOk());  

注意,之所以能够直接调用get()这样的方法是因为使用了 static import:
[java] view plain copy print?
  1. import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;  
  2. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;  
  3. import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;  


完整的测试代码如下:
[java] view plain copy print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration  
  3. public class HomeControllerTest {  
  4.     @Autowired  
  5.     private HomeController homeController;  
  6.       
  7.   
  8.     @Test  
  9.     public void testHome() throws Exception {  
  10.         MockMvc mock = MockMvcBuilders.standaloneSetup(homeController).build();  
  11.   
  12.         mock.perform(get("/")).andExpect(status().isOk())  
  13.                 .andExpect(forwardedUrl("index"));  
  14.   
  15.           
  16.           
  17.     }  

测试Service

Service方法一般会联系到数据操作,所以单纯JUnit难以进行测试。但Spring-test可以轻松应对。JUnit通过@RunWith注解将控制权交给Spring,从而让Spring启动IoC容器:
[java] view plain copy print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  

这样依赖注入就可以使用了(@Autowired注解)。但在使用之前,要配置bean,如果涉及数据库操作,还要配置LocalContainerEntityManagerFactoryBean ,就像我们在web开发中的配置一样。数据库配置bean如下:
[java] view plain copy print?
  1. /** 
  2.  * 数据库测试配置类 
  3.  * @author whf 
  4.  * 
  5.  */  
  6. @Configuration  
  7. public class DatabaseConfigure {  
  8.     @Autowired  
  9.     private DataSource dataSource;  
  10.   
  11.     @Autowired  
  12.     private EntityManagerFactory entityManagerFactory;  
  13.   
  14.   
  15.     @Bean  
  16.     public FactoryBean<EntityManagerFactory> entityManagerFactory() {  
  17.         LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();  
  18.   
  19.         emfb.setDataSource(this.dataSource);  
  20.         emfb.setJpaVendorAdapter(jpaVendorAdapter());  
  21.         emfb.setPackagesToScan("你的package");  
  22.           
  23.         Properties prop = new Properties();  
  24.         prop.put("hibernate.hbm2ddl.auto""create-drop");  
  25.         prop.put("hibernate.show_sql""true");  
  26.         prop.put("hibernate.format_sql""true");  
  27.         prop.put("hibernate.dialect""org.hibernate.dialect.H2Dialect");  
  28.           
  29.         emfb.setJpaProperties(prop);  
  30.           
  31.         return emfb;  
  32.     }  
  33.   
  34.     @Bean  
  35.     public JpaVendorAdapter jpaVendorAdapter() {  
  36.         return new HibernateJpaVendorAdapter();  
  37.     }  
  38.   
  39.     @Bean  
  40.     public PlatformTransactionManager transactionManager() {  
  41.         JpaTransactionManager txManager = new JpaTransactionManager();  
  42.         txManager.setEntityManagerFactory(this.entityManagerFactory);  
  43.         txManager.setDataSource(this.dataSource);  
  44.         return txManager;  
  45.     }  
  46.   
  47.     @Bean  
  48.     public DataSource dataSource() {  
  49.         EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();  
  50.         builder.setType(EmbeddedDatabaseType.H2);  
  51.         return builder.build();  
  52.     }  
  53. }  

这样一来我们就可以注入EntityManager了。一个完整的测试代码如下:
[java] view plain copy print?
  1. @RunWith(SpringJUnit4ClassRunner.class)  
  2. @ContextConfiguration(classes = {DatabaseConfigure.class,  
  3.         DefaultAccountService.class})  
  4. @TransactionConfiguration  
  5. @Transactional(readOnly = true)  
  6. public class AccountServiceTest {  
  7.     @Autowired  
  8.     private AccountService acService;  
  9.       
  10.     @PersistenceContext  
  11.     private EntityManager em;  
  12.       
  13.     private Member m;  
  14.       
  15.     @Before  
  16.     @Transactional(readOnly = false)  
  17.     public void initAccountData() {  
  18.         m = new Member();  
  19.         m.setUsername("bruce");  
  20.         m.setPassword("3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d");  
  21.           
  22.         em.persist(m);  
  23.     }  
  24.       
  25.     @After  
  26.     @Transactional(readOnly = false)  
  27.     public void cleanDatabase() {  
  28.         m = em.merge(m);  
  29.         em.remove(m);  
  30.     }  
  31.   
  32.       
  33.     @Test  
  34.     public void testFindByUsername() {  
  35.         Member m = acService.findMember("bruce");  
  36.         Assert.assertNotNull(m);  
  37.         Assert.assertEquals("bruce", m.getUsername());  
  38.         Assert.assertEquals("3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d", m.getPassword());  
  39.     }  

有了spring-test,省去了服务器启动和应用部署的时间,从而大大提高了开发效率,同时也减少了BUG的产生。
要运行上述测试代码,需要的maven依赖如下:
[java] view plain copy print?
  1. <dependency>  
  2.             <groupId>org.springframework</groupId>  
  3.             <artifactId>spring-test</artifactId>  
  4.             <version>${spring.version}</version>  
  5.         </dependency>  

[java] view plain copy print?
  1. <!-- JDBC连接池 -->  
  2.         <dependency>  
  3.             <groupId>commons-dbcp</groupId>  
  4.             <artifactId>commons-dbcp</artifactId>  
  5.             <version>1.4</version>  
  6.             <scope>test</scope>  
  7.         </dependency>  
  8.         <dependency>  
  9.             <groupId>com.h2database</groupId>  
  10.             <artifactId>h2</artifactId>  
  11.             <version>1.4.182</version>  
  12.             <scope>test</scope>  
  13.         </dependency>  


祝大家编码愉快~

原创粉丝点击