基于SpringBoot框架的单元测试和集成测试的区别和联系

来源:互联网 发布:mac视频投放led 编辑:程序博客网 时间:2024/05/30 05:40

1、单元测试和集成测试的区别:

  • Web集成测试:在嵌入式的Servlet容器(Tomcat,Jetty)里启动应用程序,在真正的应用服务器里进行测试。
  • Spring Mock MVC :能在一个接近真实的模拟Servlet容器里启动应用程序,而不用实际启动应用服务器,相当于单元测试。

2、可以采用Spring MVC进行单元测试,包括:

  • standaloneSetup():手工创建并配置的控制器
  • webAppContextSetup():使用应用程序上下文来构建MockMVC
    前者更加接近单元测试,专注于单一控制器的测试,后者更加接近集成测试,让Spring加载控制器以及依赖。

3、常见的单元测试的例子:

  • 单元测试代码
/** * Created by wangxx-j on 2017/12/6. */@RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@FixMethodOrder(MethodSorters.NAME_ASCENDING)@SpringBootTest(classes = {ProjectConfigApplication.class},        properties = {"EUREKA_DEFAULT_ZONE=http://192.168.xxx.xxx:10000/eureka/"})@ActiveProfiles("unit-test")public class ProjectConfigDictControllerTest extends ControllerTestSupport{    @Test    public void testQueryDefaultProjectConfig() throws Exception{        List<ProjectConfigDict> projectConfigDicts = get("/project-config-dict/query",List.class);        System.out.println("默认配置信息:"+projectConfigDicts);    }}

其中,

@WebAppConfiguration

注解表示采用的上面2中webAppContextSetup(),采用应用程序上下文来进行单元测试。

@SpringBootTest(classes = {ProjectConfigApplication.class},        properties = {"EUREKA_DEFAULT_ZONE=http://192.168.xxx.xxx:10000/eureka/"})@ActiveProfiles("unit-test")

因为我们的项目采用的是SpringCloud的框架,使用eureka服务器注册了服务,所以每个服务的配置信息都是从注册中心读取的,这里读取的是单元测试unit-test的配置。
如果你写的是一个普通的项目,那么可以将配置文件直接写到application.yml中,程序默认直接读取本地配置。

  • application.yml文件格式如下
spring:  redis:    host: 192.168.xxx.xxx    port: 6379    pool:      max-idle: 10      max-total: 20      max-wait: 2000  datasource:    druid:      driver-class-name: com.mysql.jdbc.Driver      url: jdbc:mysql://192.168.xxx.xxx:3306/unit_test_org_v3?characterEncoding=UTF-8      username: xxx      password: xxx    driver-class-name: com.mysql.jdbc.Driver    url: jdbc:mysql://192.168.xxx.xxx:3306/unit_test_org_v3?characterEncoding=UTF-8    username: xxx    password: xxx

如果,你有redis服务,就需要配置redis服务器地址,等信息。
如果你有数据库访问服务,就需要配置datasource等信息。

  • 辅助单元测试的类
    ControllerTestSupport.java
public abstract class ControllerTestSupport {    protected static MockMvc mockMvc;    private static final Long TENANT_ID = 100000L;    private static final String HEADER_TENANT_ID = "x-tenant-id";    @Autowired    private WebApplicationContext context;    private void initAction(ResultActions actions, List<CheckProperty> properties)            throws Exception {        if (null == properties || properties.size() == 0) {            return;        }        for (CheckProperty property : properties) {            if (property instanceof CheckValueProperty) {                actions.andExpect(jsonPath("$." + property.getPropertyName(), equalTo(((CheckValueProperty) property).getValue())));            } else if (property instanceof CheckNullProperty) {                boolean isNull = ((CheckNullProperty) property).isNull();                if (isNull) {                    actions.andExpect(jsonPath("$." + property.getPropertyName(), nullValue()));                } else {                    actions.andExpect(jsonPath("$." + property.getPropertyName(), notNullValue()));                }            }        }    }    protected <T> T put(String uriPath, Object data,                        List<CheckProperty> properties, Class<T> tClass)            throws Exception {        ResultActions actions = getMockMvc().perform(                MockMvcRequestBuilders                        .put(uriPath)                        .header(HEADER_TENANT_ID, TENANT_ID)                        .content(JSON.toJSONBytes(data))                        .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)                        .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))                .andExpect(status().isOk());        initAction(actions, properties);        MvcResult mvcResult = actions.andReturn();        return convert(mvcResult, tClass);    }    protected <T> T get(String uriPath, Class<T> tClass)            throws Exception {        return get(uriPath, tClass, HttpStatus.OK.value());    }    protected <T> T get(String uriPath, Class<T> tClass, int status)            throws Exception {        MvcResult mvcResult = getMockMvc().perform(                MockMvcRequestBuilders                        .get(uriPath)                        .header(HEADER_TENANT_ID,TENANT_ID)                        .contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)                        .accept(MediaType.APPLICATION_JSON_UTF8_VALUE))                .andExpect(status().is(status))                .andReturn();        return convert(mvcResult, tClass);    }    protected <T> T convert(MvcResult mvcResult, Class<T> tClass) throws Exception {        if (null == tClass) {            return null;        }        String content = mvcResult.getResponse().getContentAsString();        T actionResult = JSONObject.parseObject(content, tClass);        return actionResult;    }    private synchronized MockMvc getMockMvc() {        if (null == mockMvc) {            mockMvc = MockMvcBuilders.webAppContextSetup(context).build();        }        return mockMvc;    }}

其中,我们看到:
initAction函数是在post、get方法中调用的,主要是处理一些特殊的属性,比如有枚举类型的。
convert方法是为了得到返回的结果,将json转化为对应的类。
getMockMvc是模拟上下文构建Servlet容器,和第二点的webAppContextSetup对应。

CheckProperty.java:

@Data@NoArgsConstructor@AllArgsConstructorpublic class CheckProperty {    private String propertyName;}


CheckValueProperty .java:

@Data@EqualsAndHashCode(callSuper = true)public class CheckValueProperty extends CheckProperty {    private Object value;    public CheckValueProperty(String name, Object value) {        super(name);        setValue(value);    }}


CheckNullProperty .java:

@Data@EqualsAndHashCode(callSuper = true)public class CheckNullProperty extends CheckProperty {    private boolean isNull;    public CheckNullProperty(String name, boolean isNull) {        super(name);        setNull(isNull);    }}
阅读全文
0 0
原创粉丝点击