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

文章要点:

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

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

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

测试Controller

当我们编写完一个Controller后,常规的测试方式就是部署运行应用,然后观察运行效果。如果想要编写测试,也要用Mock对象模拟请求参数,模拟HttpSession,特别麻烦。现在spring-test为我们提供了一个更加优雅的测试方式。例如,要测试下面的Controller:

@RequestMapping(value = {"/", "/shop"}, method = RequestMethod.GET)
	public String home() {
		return "index";
	}

其对应的测试代码为:

@Test
	public void testHome() throws Exception {
		MockMvc mock = MockMvcBuilders.standaloneSetup(homeController).build();

		mock.perform(get("/")).andExpect(status().isOk())
				.andExpect(forwardedUrl("index"));

	}

在测试代码中,我们向 HomeController 发送GET请求 "/", 然后判断(andExpect()方法)HTTP状态码是否为200,再判断是否跳转到了"index"页面。如果有任何一环出错,测试就会失败。

我们也可以传送请求参数:

mock.perform(get("/").param("username", "password"))
			.andExpect(status().isOk());

注意,之所以能够直接调用get()这样的方法是因为使用了 static import:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

完整的测试代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class HomeControllerTest {
	@Autowired
	private HomeController homeController;

	@Test
	public void testHome() throws Exception {
		MockMvc mock = MockMvcBuilders.standaloneSetup(homeController).build();

		mock.perform(get("/")).andExpect(status().isOk())
				.andExpect(forwardedUrl("index"));

	}

测试Service

Service方法一般会联系到数据操作,所以单纯JUnit难以进行测试。但Spring-test可以轻松应对。JUnit通过@RunWith注解将控制权交给Spring,从而让Spring启动IoC容器:

@RunWith(SpringJUnit4ClassRunner.class)

这样依赖注入就可以使用了(@Autowired注解)。但在使用之前,要配置bean,如果涉及数据库操作,还要配置LocalContainerEntityManagerFactoryBean ,就像我们在web开发中的配置一样。数据库配置bean如下:

/**
 * 数据库测试配置类
 * @author whf
 *
 */
@Configuration
public class DatabaseConfigure {
	@Autowired
	private DataSource dataSource;

	@Autowired
	private EntityManagerFactory entityManagerFactory;

	@Bean
	public FactoryBean<EntityManagerFactory> entityManagerFactory() {
		LocalContainerEntityManagerFactoryBean emfb = new LocalContainerEntityManagerFactoryBean();

		emfb.setDataSource(this.dataSource);
		emfb.setJpaVendorAdapter(jpaVendorAdapter());
		emfb.setPackagesToScan("你的package");

		Properties prop = new Properties();
		prop.put("hibernate.hbm2ddl.auto", "create-drop");
		prop.put("hibernate.show_sql", "true");
		prop.put("hibernate.format_sql", "true");
		prop.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");

		emfb.setJpaProperties(prop);

		return emfb;
	}

	@Bean
	public JpaVendorAdapter jpaVendorAdapter() {
		return new HibernateJpaVendorAdapter();
	}

	@Bean
	public PlatformTransactionManager transactionManager() {
		JpaTransactionManager txManager = new JpaTransactionManager();
		txManager.setEntityManagerFactory(this.entityManagerFactory);
		txManager.setDataSource(this.dataSource);
		return txManager;
	}

	@Bean
	public DataSource dataSource() {
		EmbeddedDatabaseBuilder builder = new EmbeddedDatabaseBuilder();
		builder.setType(EmbeddedDatabaseType.H2);
		return builder.build();
	}
}

这样一来我们就可以注入EntityManager了。一个完整的测试代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DatabaseConfigure.class,
		DefaultAccountService.class})
@TransactionConfiguration
@Transactional(readOnly = true)
public class AccountServiceTest {
	@Autowired
	private AccountService acService;

	@PersistenceContext
	private EntityManager em;

	private Member m;

	@Before
	@Transactional(readOnly = false)
	public void initAccountData() {
		m = new Member();
		m.setUsername("bruce");
		m.setPassword("3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d");

		em.persist(m);
	}

	@After
	@Transactional(readOnly = false)
	public void cleanDatabase() {
		m = em.merge(m);
		em.remove(m);
	}

	@Test
	public void testFindByUsername() {
		Member m = acService.findMember("bruce");
		Assert.assertNotNull(m);
		Assert.assertEquals("bruce", m.getUsername());
		Assert.assertEquals("3d4f2bf07dc1be38b20cd6e46949a1071f9d0e3d", m.getPassword());
	}

有了spring-test,省去了服务器启动和应用部署的时间,从而大大提高了开发效率,同时也减少了BUG的产生。

要运行上述测试代码,需要的maven依赖如下:

<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
<!-- JDBC连接池 -->
		<dependency>
			<groupId>commons-dbcp</groupId>
			<artifactId>commons-dbcp</artifactId>
			<version>1.4</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<version>1.4.182</version>
			<scope>test</scope>
		</dependency>

祝大家编码愉快~

时间: 2024-11-05 20:26:22

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

Spring MVC Junit4 单元测试

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/config/spring3/applicationContext.xml" })//启动Spring容器 public class TestISrmVendorService { //注入Spring容器中的Bean @Autowired private ISrmVendorService srmVendorService; @T

Spring MVC Controller 单元测试

简介 Controller层的单元测试可以使得应用的可靠性得到提升,虽然这使得开发的时间有所增加,有得必失,这里我认为得到的比失去的多很多. Sping MVC3.2版本之后的单元测试方法有所变化,随着功能的提升,单元测试更加的简单高效. 这里以4.1版本为例,记录Controller的单元测试流程.非常值得参考的是Spring MVC Showcase(https://github.com/spring-projects/spring-mvc-showcase),它当前的版本使用的是4.1.0

Spring MVC -- 应用测试

测试在软件开发中的重要性不言而喻.测试的主要目的是尽早发现错误,最好是在代码开发的同时.逻辑上认为,错误发现的越早,修复的成本越低.如果在编程中发现错误,可以立即更改代码:如果软件发布后,客户发现错误所需要的修复成本会很大. 在软件开发中有许多不同的测试,其中两个是单元测试和集成测试.通常从单元测试开始测试类中的单个方法,然后进行集成测试,以测试不同的模块是否可以无缝协同工作. 本篇博客中的示例使用JUnit测试框架以及Spring test模块.Spring test模块中的API可用于单元测

如何在Spring MVC工程中进行单元测试

直接以代码方式演示如何在Spring MVC工程中进行单元测试: package net.chinaedu.projects.dubhe; import java.util.List; import net.chinaedu.projects.dubhe.publisher.IPublisherService; import net.chinaedu.projects.venus.domain.Publisher; import org.junit.Test; import org.junit.

2017.3.31 spring mvc教程(五)Action的单元测试

学习的博客:http://elf8848.iteye.com/blog/875830/ 我项目中所用的版本:4.2.0.博客的时间比较早,11年的,学习的是Spring3 MVC.不知道版本上有没有变化比较大的功能. spring mvc教程(五)Action的单元测试 这里的博客,还不支持@ContextConfiguration的注解式context file注入.所以内容就不写了. 等找到最新的单元测试方式,再来总结.

使用Mock 对spring mvc 的controller层进行单元测试

总体目标:达到自动化测试接口的目的 项目组成:spring mvc + hibernate + mysql 如何使用mock进行接口的单元测试? 实现思路:将mysql替换成h2数据库,之前hibernate 的datesource配置的是mysql,现在配置成h2,这样测试的数据库是干净的,因为在内存中.每次进行junit mock测试之前清空一下内存中的数据库即可 实现代码: package cn.edu.hebtu.www.onemeet.client.controller; import

Spring mvc 4系列教程(三)—— Spring4.X的新特性

1.Spring4.0的新特性 从2004年Spring的1.0发布后,后面又发布了很多重要的版本:Spring2.0提供了XML命令空间和AspectJ的支持:Spring2.5提出了注解驱动(annotation-driven)配置:Spring3.0引入了跨框架代码库的java 5+.基于java的Configuration模型等. Spring 4.0是最近发布的主要版本,而且对java8完全支持.当然,你可以继续使用低版本的java,但最低只能是java SE6.Spring 4.0里

玩转单元测试之Testing Spring MVC Controllers

玩转单元测试之 Testing Spring MVC Controllers 转载注明出处:http://www.cnblogs.com/wade-xu/p/4311657.html The Spring MVC Test framework provides first class JUnit support for testing client and server-side Spring MVC code through a fluent API. Typically it loads t

浅析Spring MVC和Spring BOOT之间的简化小秘密

从Servlet技术到Spring和Spring MVC,开发Web应用变得越来越简捷.但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的朋友能深刻体会到这一痛苦.因为即使是开发一个Hello-World的Web应用,都需要我们在pom文件中导入各种依赖,编写web.xml.spring.xml.springmvc.xml配置文件等.特别是需要导入大量的jar包依赖时,我们需要在网上查找各种jar包资源,各个jar间可能存在着各种依赖关系,