当前位置 : 首页 » 文章分类 :  开发  »  Spring-Test

Spring-Test

Spring/Spring Boot/JUnit 测试相关笔记

首先要分清几个概念:测试方法、测试类、测试集、测试运行器。

  • 测试方法就是用@Test注解的一些函数。
  • 测试类是包含一个或多个测试方法的一个**Test.java文件
  • 测试集是一个suite,可能包含多个测试类。
  • 测试运行器则决定了用什么方式偏好去运行这些测试集/类/方法。

@Transactional 测试数据自动回滚

可以实现再springboot中使用junit编写单元测试,并且测试结果不影响数据库。

@Transactional 表示该方法整体为一个事务,可以用在测试类上表示所有测试方法都回滚,或具体的 @Test 方法上。
@Rollback 表示事务执行完回滚,支持传入一个参数value,默认true即回滚,false不回滚。

springboot中junit回滚
https://www.jianshu.com/p/d9d0abf317c0


使用MockMvc测试Spring MVC Controller

用到的注解:
@RunWith(SpringJUnit4ClassRunner.class): 表示使用Spring Test组件进行单元测试;
@WebAppConfiguration: 使用这个Annotate会在跑单元测试的时候真实的启动一个web服务,然后开始调用Controller的Rest API,待单元测试跑完之后再将web服务停掉;
@ContextConfiguration: 指定Bean的配置文件信息,可以有多种方式,这个例子使用的是文件路径形式,如果有多个配置文件,可以将括号中的信息配置为一个字符串数组来表示;controller,component等都是使用注解,需要注解指定spring的配置文件,扫描相应的配置,将类初始化等。
@TransactionConfiguration(transactionManager=”transactionManager”,defaultRollback=true)配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用

为什么要进行事务回滚:
1、测试过程对数据库的操作,会产生脏数据,影响我们数据的正确性
2、不方便循环测试,即假如这次我们将一个记录删除了,下次就无法再进行这个Junit测试了,因为该记录已经删除,将会报错。
3、如果不使用事务回滚,我们需要在代码中显式的对我们的增删改数据库操作进行恢复,将多很多和测试无关的代码

测试类基类

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.transaction.TransactionConfiguration;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.WebApplicationContext;

//这个必须使用junit4.9以上才有
@RunWith(SpringJUnit4ClassRunner.class)
//单元测试的时候真实的开启一个web服务
@WebAppConfiguration
//配置事务的回滚,对数据库的增删改都会回滚,便于测试用例的循环利用
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=true)
@Transactional
@ContextConfiguration(locations = {"classpath:spring.xml","classpath:spring-hibernate.xml"})
public class AbstractContextControllerTests {

    @Autowired
    protected WebApplicationContext wac;
}

具体测试类

package com.pengtu.gsj;

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

import org.hibernate.SessionFactory;
import org.junit.Before;
import org.junit.Test;
import org.owasp.esapi.ESAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import com.pengtu.gsj.controller.BannerController;
import com.pengtu.gsj.dao.UserDao;
import com.pengtu.gsj.entity.app.User;
import com.pengtu.gsj.service.UserService;


public class EsapiTest extends AbstractContextControllerTests{

    private MockMvc mockMvc;
    //该方法在每个方法执行之前都会执行一遍
    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders.standaloneSetup(new BannerController()).build();
    }

    /**
     * perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;
     * get:声明发送一个get请求的方法。MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板        和uri变量值得到一个GET请求方式的。另外提供了其他的请求的方法,如:post、put、delete等。
     * param:添加request的参数,如上面发送请求的时候带上了了pcode = root的参数。假如使用需要发送json数据格式的时将不能使用这种        方式,可见后面被@ResponseBody注解参数的解决方法
     * andExpect:添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确(对返回的数据进行的判断);
     * andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台(对返回的数据进行的判断);
     * andReturn:最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理(对返回的数据进行的判断)
     * @throws Exception
     */
    @Test
    public void getAllBanners() throws Exception{
         String responseString = mockMvc.perform(get("/banner/hello")    //请求的url,请求的方法是get
                            .contentType(MediaType.APPLICATION_JSON)  //数据的格式
                            .param("id","123456789")         //添加参数
            ).andExpect(status().isOk())    //返回的状态是200
                    .andDo(print())         //打印出请求和相应的内容
                    .andReturn().getResponse().getContentAsString();   //将相应的数据转换为字符串
            System.out.println("--------返回的json = " + responseString);
    }
}

perform:执行一个RequestBuilder请求,会自动执行SpringMVC的流程并映射到相应的控制器执行处理;
get:声明发送一个get请求的方法。MockHttpServletRequestBuilder get(String urlTemplate, Object… urlVariables):根据uri模板和uri变量值得到一个GET请求方式的。另外提供了其他的请求的方法,如:post、put、delete等。
param:添加request的参数,如上面发送请求的时候带上了了pcode = root的参数。假如使用需要发送json数据格式的时将不能使用这种方式。
andExpect:添加ResultMatcher验证规则,验证控制器执行完成后结果是否正确(对返回的数据进行的判断);
andDo:添加ResultHandler结果处理器,比如调试时打印结果到控制台(对返回的数据进行的判断);
andReturn:最后返回相应的MvcResult;然后进行自定义验证/进行下一步的异步处理(对返回的数据进行的判断)

使用MockMvc测试Spring mvc Controller
https://blog.csdn.net/zhang289202241/article/details/62042842


SpringRunner和SpringJUnit4ClassRunner

SpringRunner 是 SpringJUnit4ClassRunner 的别名,两者没有任何区别

What is the difference between SpringJUnit4ClassRunner and SpringRunner
https://stackoverflow.com/questions/47446529/what-is-the-difference-between-springjunit4classrunner-and-springrunner

Class SpringRunner
https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/test/context/junit4/SpringRunner.html


spring boot单元测试

1、要让一个普通类变成一个单元测试类只需要在类名上加入 @SpringBootTest 和 @RunWith(SpringRunner.class) 两个注释即可。
2、在测试方法上加上 @Test 注释。

Spring Boot 单元测试详解+实战教程
https://www.cnblogs.com/javastack/p/9150408.html


@SpringBootTest

@SpringBootTest 为springApplication创建上下文并支持SpringBoot特性

@SpringBootTest 的webEnvironment属性有以下4种
1、Mock —— 加载WebApplicationContext并提供Mock Servlet环境
2、RANDOOM_PORT —— 加载EmbeddedWebApplicationContext并提供servlet环境,内嵌服务的监听端口是随机的
3、DEFINED_PORT —— 加载EmbeddedWebApplicationContext并提供servlet环境,内容服务的监听端口是定义好的。默认端口是8080
4、NONE —— 加载ApplicationContext,启动SpringApplication时,不支持Servlet环境

Spring Test单元测试
http://jianwl.com/2016/08/07/Spring-Test%E5%8D%95%E5%85%83%E6%B5%8B%E8%AF%95/

Annotation Type SpringBootTest
https://docs.spring.io/spring-boot/docs/current/api/org/springframework/boot/test/context/SpringBootTest.html


@TestPropertySource 设置System Property

@TestPropertySource 可以用来覆盖掉来自于系统环境变量、Java系统属性、@PropertySource的属性。

同时@TestPropertySource(properties=…)优先级高于@TestPropertySource(locations=…)。

利用它我们可以很方便的在测试代码里微调、模拟配置(比如修改操作系统目录分隔符、数据源等)。

Spring、Spring Boot和TestNG测试指南 - @TestPropertySource
https://segmentfault.com/a/1190000010854607

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:whereever/context.xml")
@TestPropertySource(properties = {"myproperty = foo"})
public class TestWarSpringContext {
    ...
}

How to set environment variable or system property in spring tests?
https://stackoverflow.com/questions/11306951/how-to-set-environment-variable-or-system-property-in-spring-tests


@ClassRule 和 @Rule

junit中的 @ClassRule,可以在所有类方法开始前进行一些初始化调用,比如创建临时文件,

package com.jdriven;

import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;

import java.io.File;
import java.io.IOException;

public class JUnitClassRuleTest {


    @ClassRule
    public static TemporaryFolder temporaryFolder = new TemporaryFolder();

    public static File tempFile;

    @BeforeClass
    public static void createTempFile() throws IOException {
        tempFile = temporaryFolder.newFile("tempFile.txt");
    }

    @Test
    public void testJUnitClassRule_One() {
        //Your test should go here, which uses tempFile
    }

    @Test
    public void testJUnitClassRule_Two() {
        //Your test should go here and uses the same tempFile
    }
}

其中,@ClassRule中指定创建临时文件夹,这是在所有的测试方法前会创建文件夹,并且会在所有测试完成后,递归删除其下的子目录和子文件夹。

@Rule 是方法级别的,每个测试方法执行时都会调用被注解的Rule,而@ClassRule是类级别的,在执行一个测试类的时候只会调用一次被注解的Rule

junit中的@classrule,@rule
http://jackyrong.iteye.com/blog/2193451


@RunWith

@RunWith指定JUnit使用的单元测试执行类,使用@RunWith注解可以改变JUnit的默认执行类
@Runwith放在测试类名之前,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器。

常见的运行器有:

  • 参数化运行器
    @RunWith(Parameterized.class) 参数化运行器,配合@Parameters使用junit的参数化功能

  • 测试集运行器
    @RunWith(Suite.class)
    @SuiteClasses({ATest.class,BTest.class,CTest.class})
    测试集运行器配合使用测试集功能

  • junit4的默认运行器
    @RunWith(JUnit4.class)
    junit4的默认运行器

  • 兼容junit3.8的运行器
    @RunWith(JUnit38ClassRunner.class)
    用于兼容junit3.8的运行器

  • SpringJUnit4ClassRunner
    @RunWith(SpringJUnit4ClassRunner.class)集成了spring的一些功能

junit常用注解详细说明
http://www.cnblogs.com/tobey/p/4837495.html

使用RunWith注解改变JUnit的默认执行类,并实现自已的Listener
http://blog.csdn.net/fenglibing/article/details/8584602


@Test

在junit3中,是通过对测试类和测试方法的命名来确定是否是测试,且所有的测试类必须继承junit的测试基类。在junit4中,定义一个 测试方法变得简单很多,只需要在方法前加上@Test就行了。

注意:测试方法必须是public void,即公共、无返回数据。可以抛出异常。

junit常用注解详细说明
http://www.cnblogs.com/tobey/p/4837495.html


@ContextConfiguration

@ContextConfiguration注解用于指定spring配置文件所在的路径,有以下两个常用的属性:

  • locations:可以通过该属性手工指定 Spring 配置文件所在的位置,可以指定一个或多个 Spring 配置文件。如下所示:

    @ContextConfiguration(locations = {"xx/yy/beans1.xml","xx/yy/beans2.xml"})
    @ContextConfiguration(locations = "classpath*:spring-ctx-*.xml")
    
  • inheritLocations:是否要继承父测试用例类中的 Spring 配置文件,默认为 true。如下面的例子:

    @ContextConfiguration(locations={"base-context.xml"})
    public class BaseTest {
    // ...
    }
    @ContextConfiguration(locations={"extended-context.xml"})
    public class ExtendedTest extends BaseTest {
    // ...
    }
    

    如果 inheritLocations 设置为 false,则 ExtendedTest 仅会使用 extended-context.xml 配置文件,否则将使用 base-context.xml 和 extended-context.xml 这两个配置文件。

Spring基于注解TestContext 测试框架使用详解
http://blog.csdn.net/yaerfeng/article/details/25368447

Spring 注解学习手札(六) 测试
http://snowolf.iteye.com/blog/588351


上一篇 Nginx

下一篇 Hexo博客(23)弃用七牛云图床改为git仓库图床

阅读
2,670
阅读预计11分钟
创建日期 2018-10-09
修改日期 2018-10-18
类别
百度推荐