Spring 的 SpringJUnit4ClassRunner可以在基于JUnit的应用程序测试里加载Spring 应用程序上下文。在测试Spring Boot应用程序时,Spring Boot除了拥有Spring的集成测试支持,还开启了自动配置和web服务器,并提供了不少实用的测试辅助工具
spring 测试
集成测试
spring TestContext Framework
上下文管理
@ContextConfiguration
@ContextHierarchy
@WebAppConfiguration
@DirtiesContext
依赖注入
事务管理
@BeforeTransaction
@AfterTransaction
@Commit
@Rollback
JDBC测试支持
spring webmvc Test Framework
服务端测试
HtmlUnit 集成
客户端测试
spring boot 测试
注解
@SpringBootTest
配置属性
Spring Bean 配置
Web 环境
自动装配测试
JSON
Spring WebMVC
Data JPA
JDBC
RestClient
Spring 集成测试:
spring boot 1.5.14
实体类 |
package cn.shendu.springbootlesson19.domain;
public class Person { private String id; private String name; private Integer age;
public String getId() { return id; }
public void setId(String id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Integer getAge() { return age; }
public void setAge(Integer age) { this.age = age; } } |
配置类 |
package cn.shendu.springbootlesson19.configuration;
import cn.shendu.springbootlesson19.domain.Person; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Primary;
@Configuration public class PersonConfiguration {
@Bean("primaryPerson") @Primary public Person person(){ Person person = new Person(); person.setId("1"); person.setName("shendu"); person.setAge(24); return person; }
} |
编写监听器,可以监控测试上下文,例如在方法执行前做出提示
|
package cn.shendu.springbootlesson19.listener;
import cn.shendu.springbootlesson19.domain.Person; import org.springframework.context.ApplicationContext; import org.springframework.test.context.TestContext; import org.springframework.test.context.support.AbstractTestExecutionListener;
public class PersonIegrationTestListener extends AbstractTestExecutionListener{
public void beforeTestMethod(TestContext testContext) throws Exception {
/* ApplicationContext applicationContext = testContext.getApplicationContext(); applicationContext.getBean("primaryPerson", Person.class)*/
System.err.println("before: "+ testContext.getTestMethod()); }
public void afterTestMethod(TestContext testContext) throws Exception { System.err.println("after: "+testContext.getTestMethod()); }
} |
编写集成测试类: |
package cn.shendu.springbootlesson19;
import cn.shendu.springbootlesson19.configuration.PersonConfiguration; import cn.shendu.springbootlesson19.domain.Person; import cn.shendu.springbootlesson19.listener.PersonIegrationTestListener; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.ContextHierarchy; import org.springframework.test.context.TestExecutionListeners; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
@RunWith(SpringRunner.class) // 执行时先运行 SpringRunner 这部分 装载 @ContextHierarchy({ @ContextConfiguration( classes = PersonConfiguration.class // 相当于注册PersonConfiguration 这个bean ) } ) /* TestExecutionListener TestExecutionListeners 添加后 覆盖了
org.springframework.test.context.web.ServletTestExecutionListener,\ org.springframework.test.context.support.DirtiesContextBeforeModesTestExecutionListener,\ org.springframework.test.context.support.DependencyInjectionTestExecutionListener,\ org.springframework.test.context.support.DirtiesContextTestExecutionListener,\ org.springframework.test.context.transaction.TransactionalTestExecutionListener,\ org.springframework.test.context.jdbc.SqlScriptsTestExecutionListener
这些行为
所以要 加上 依赖 */ @TestExecutionListeners(listeners = {PersonIegrationTestListener.class, DependencyInjectionTestExecutionListener.class}) //测试上下文 public class PersonIegrationTest { @Autowired private Person person;
@Before public void methodBefore(){ System.err.println("methodBefore"); }
@Test public void testPrimaryPerson(){ Assert.assertEquals("shendu",person.getName());
}
@After public void methodAfter(){ System.err.println("methodAfter"); }
} |
Spring Boot集成测试,
只加载 PersonConfiguration |
package cn.shendu.springbootlesson19.spring.boot;
import cn.shendu.springbootlesson19.configuration.PersonConfiguration; import cn.shendu.springbootlesson19.domain.Person; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class) @SpringBootTest(classes = PersonConfiguration.class) // 细粒度,模块化的测试 public class PersonSpringBootTest { @Autowired private Person person;
@Test public void testPrimaryPerson(){ Assert.assertEquals("shendu",person.getName());
} } |
web mvc 测试
|
package cn.shendu.springbootlesson19.spring.boot;
import cn.shendu.springbootlesson19.configuration.PersonConfiguration; import cn.shendu.springbootlesson19.controller.PersonController; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.context.annotation.Import; import org.springframework.http.MediaType; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringRunner.class) @WebMvcTest(PersonController.class) @Import(PersonConfiguration.class) public class PersonControllerSpringBootTest { @Autowired private MockMvc mvc;
@Test public void testPerson() throws Exception { mvc.perform(get("/person").accept(MediaType.APPLICATION_JSON_UTF8)). andExpect(status().isOk()); }
} |
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @BootstrapWith(WebMvcTestContextBootstrapper.class) @OverrideAutoConfiguration(enabled = false) @TypeExcludeFilters(WebMvcTypeExcludeFilter.class) @AutoConfigureCache @AutoConfigureWebMvc @AutoConfigureMockMvc @ImportAutoConfiguration public @interface WebMvcTest {
web mvc test 接口 , 实际上 导入 了 @AutoConfigureMockMvc,spring 实际上 是根据情况,导入 spring-boot-test-autoconfigure-1.5.8.RELEASE.jar!\META-INF\spring.factories 下的类,从而达到细粒度测试的目的
|
spring.factories 部分代码 |
# AutoConfigureMockMvc auto-configuration imports org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc=\ org.springframework.boot.test.autoconfigure.web.servlet.MockMvcAutoConfiguration,\ org.springframework.boot.test.autoconfigure.web.servlet.MockMvcSecurityAutoConfiguration,\ org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebClientAutoConfiguration,\ org.springframework.boot.test.autoconfigure.web.servlet.MockMvcWebDriverAutoConfiguration |
参考:
小马哥spring boot 教程
Spring Boot实战 ,丁雪丰 (译者)