SpringBoot | 第十三章:测试相关(单元测试、性能测试)

栏目: Java · 发布时间: 5年前

内容简介:前面写了这么多章节,都是通过浏览器访问的形式,进行接口方法访问进而验证方法的正确与否。显然在服务或者接口比较少时,这么做没有啥问题,但一旦一个项目稍微复杂或者接口方法比较多时,这么验证就有点不符合程序猿的是指对软件中的最小可对于

前言

前面写了这么多章节,都是通过浏览器访问的形式,进行接口方法访问进而验证方法的正确与否。显然在服务或者接口比较少时,这么做没有啥问题,但一旦一个项目稍微复杂或者接口方法比较多时,这么验证就有点不符合程序猿的 懒人 的特性了。所以这章节,讲述下 SpringBoot 中的单元测试及基于 Contiperf 压测 工具 进行性能测试相关方面的知识点。

单元测试

是指对软件中的最小可 测试单元 进行检查和验证。一般上在开发阶段或者程序发布时,都会利用像 Maven 这样的打包工具进行打包前的测试,避免不必要的bug程序被打包部署。

题外话:在开发阶段,都应该要求编写单元测试,核心的模块还需要进行覆盖测试,覆盖率至少要95%以上。

SpringBoot的单元测试

对于 java 开发者而言, Junit 应该无人不知了。所以 SpringBoot 也是基于 Junit 进行单位测试的。

0.加入pom依赖。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

1.这里为了演示,编写了一个简单的测试接口及编写对应的测试类。

UnitTestService.java

/**
 * 测试接口类
 * @author oKong
 *
 */
public interface UnitTestService {
    
    public String process(String msg);

}

实现类:UnitTestServiceImpl.java

@Service
public class UnitTestServiceImpl implements UnitTestService{

    /**
     * 为了测试,这里直接返回传入的值
     */
    @Override
    public String process(String msg) {
        // TODO Auto-generated method stub
        return msg;
    }
}

测试类:UnitTestServiceTest.java

题外话:个人建议,每个测试类都应该和对应的被测试类包路径一致。同时测试类的名称是被测试的类名+Test,如本例所示的:

SpringBoot | 第十三章:测试相关(单元测试、性能测试)

/**
 * 编写接口测试类
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
public class UnitTestServiceTest {
    
    @Autowired
    UnitTestService testService;
    
    public void test() {
        String msg = "this is a test";
        String result = testService.process(msg);
        //断言 是否和预期一致
        Assert.assertEquals(msg, result);
    }
}
  1. 运行右击,选择  run As  –>  Junit Test  或者需要debug时,选择 Debug As  –>  Junit Test ,运行即可。

SpringBoot | 第十三章:测试相关(单元测试、性能测试)

3.至此,一个简单的单元测试就结束了。 简单来说,写一个单元测试是容易的,但写好一个单元测试是难的。 毕竟,每个程序猿都觉得自己的代码是没有问题的,难道不是吗?哈哈!

RESTful API 单元测试

对于服务类而言,编写单元测试是相对简单的,只需要像控制层自动引入接口类一样。但编写控制层即RESTful API 单元测试时,一般上就需要利用 Mock 技术进行测试了。当然也可以使用像 Swagger 或者 PostMan 这样的api测试工具进行测试(或者使用 RestTemplate 测试也是可行的),它可进行自动化测试,关于 Postman 会在之后的章节进行更新,作者也没有过多研究过,也只是用到了它的最基本的发起http请求的功能,之后会整理相关资料的。

0.创建一个RESTful接口服务。

/**
 * 编写mock测试服务
 * @author oKong
 *
 */
@RestController
public class DemoController {

    @GetMapping("/mock")
    public String demo(String msg) {
        return msg;
    }
}

1.编写对应测试类

@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
//因为是mock测试,在实际开发过程中,可指定其测试启动时为随机端口,避免了不必要的端口冲突。
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) 
//测试单一接口时 ,也可利用注解@WebMvcTest 进行单一测试
//@WebMvcTest(DemoController.class)
public class DemoControllerTest {

    //使用 WebMvcTest 时使用 
    //@autowired mockMvc 是可自动注入的。
    //当直接使用SpringBootTest 会提示 注入失败  这里直接示例利用 MockMvcBuilders工具创建
    //@Autowired
    MockMvc mockMvc;
    
    @Autowired
    WebApplicationContext wc;
    
    @Before
    public void beforeSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wc).build();
    }
    
    @Test
    public void testDemo() throws Exception {
        String msg = "this is a mock test";
        MvcResult result = this.mockMvc.perform(get("/mock").param("msg", msg)).andDo(print()).andExpect(status().isOk())
        .andReturn();
        
        //断言 是否和预期相等
        Assert.assertEquals(msg, result.getResponse().getContentAsString());

    }
}

2.运行右击,选择 run As –>  Junit Test 或者需要debug时,选择 Debug As –>  Junit Test ,运行即可。(也可以看见每次启动测试时,每次端口号都是不同的。)

2018-07-25 23:16:28.733  INFO 13000 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 59999 (http)
2018-07-25 23:16:28.754  INFO 13000 --- [           main] c.l.l.s.c.controller.DemoControllerTest  : Started DemoControllerTest in 5.673 seconds (JVM running for 6.769)

SpringBoot | 第十三章:测试相关(单元测试、性能测试)

由于配置了 print() 这个 ResultHandler ,所以控制台会打印相关参数信息。 建议设置此属性,这样就算测试有问题,也能看下具体的参数信息。其他相关mock的用法,此处就不举例了,大家可自行搜索下,比较本章节只是简单示例下用法~

SpringBoot | 第十三章:测试相关(单元测试、性能测试)

  1. 鉴于每次编写控制层测试类时,都需要创建 MockMvc 对象,故可创建一个基类,这样省得每次都写。

BaseMockTest.java

/**
 * mock 基类
 * @author oKong
 *
 */
public abstract class BaseMockTest {
    
    @Autowired
    private WebApplicationContext wc;

    protected MockMvc mockMvc;
    
    @Before
    public void beforeSetUp() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(wc).build();
    }

}

这样编写mock测试类时,还需要继承此基类即可。

Junit常用注解说明

  • @Test 加在 待测试的方法 前面
  • @Before 带上@Test的方法执行前会执行该方法
  • @After 带上@Test的方法执行完毕后会执行该方法
  • @BeforeClass 加上这个注解,则该方法会第一个执行(在所有方法中),且方法要 加上关键词static ,是一个 static方法
  • @AfterClass 加上这个注解,则该方法最后一个执行(在所有方法中),同样,方法要 加上关键词static ,是一个 static方法

详细的使用,大家可自行谷歌下,毕竟常用的也就前面三个了,(┬_┬)

基于ContiPerf的性能测试

ContiPerf是一个轻量级的测试工具,基于JUnit 4 开发,可用于效率测试等。可以指定在线程数量和执行次数,通过限制最大时间和平均执行时间来进行性能测试。

性能测试示例

0.加入pom依赖包。

<dependency>
    <groupId>org.databene</groupId>
    <artifactId>contiperf</artifactId>
    <version>2.3.4</version>
    <scope>test</scope>
</dependency>

1.改写 UnitTestServiceTest 测试类,进入 ContiPerfRule

题外话: @RuleJunit 提供的一个扩展接口注解,其接口类为: org.junit.rules.MethodRule ,注意在Junit5中,已经被 TestRule 所以替代了。这里只是简单提下,因为具体的也不是很清楚,也没有深入了解过。

/**
 * 编写接口测试类
 * @author oKong
 *
 */
@RunWith(SpringRunner.class)
//SpringBootTest 是springboot 用于测试的注解,可指定启动类或者测试环境等,这里直接默认。
@SpringBootTest 
public class UnitTestServiceTest {
	
	@Autowired
	UnitTestService testService;
	
	//引入 ContiPerf 进行性能测试
	@Rule
	public ContiPerfRule contiPerfRule = new ContiPerfRule();
	
	@Test
	//10个线程 执行10次
	@PerfTest(invocations = 100,threads = 10)
	public void test() {
		String msg = "this is a test";
		String result = testService.process(msg);
		//断言 是否和预期一致
		Assert.assertEquals(msg, result);
	}
}
  1. 控制台会有性能报告,同时访问: target/contiperf-report/index.html ,会有图表提示。

控制台输出:

cn.lqdev.learning.springboot.chapter13.service.UnitTestServiceTest.test
samples: 100
max:     403
average: 41.5
median:  15

测试报告:

SpringBoot | 第十三章:测试相关(单元测试、性能测试) 测试报告

注解参数说明

@PerfTest

  • invocations:执行次数n,与线程数量无关,默认值为1
  • threads:线程池数量n,并发执行n个线程
  • duration:重复地执行时间n,测试至少执行n毫秒

@Required

  • throughput:吞吐要求n,要求每秒至少执行n个测试
  • average:平均执行时间n,要求平均执行时间不超过n毫秒
  • max:最大执行时间n,要求最大的执行时间不超过n毫秒
  • totalTime:总执行时间n,要求总的执行时间不超过n毫秒
  • median:50%平均执行时间n,要求所有执行的50%测试平均执行时间不超过n毫秒
  • percentile90:90%平均执行时间n,要求所有执行的90%测试平均执行时间不超过n毫秒
  • percentile95:95%平均执行时间n,要求所有执行的95%测试平均执行时间不超过n毫秒
  • percentile99:99%平均执行时间n,要求所有执行的99%测试平均执行时间不超过n毫秒
  • percentiles:表达式”a:n,b:m”,要求a%的测试不超过n毫秒,b%的测试不超过m毫秒

总结

本章节主要是对 JunitContiPerf 的使用简单的示例,像 MockMvc 的详细用法并没有深入,大家可自行搜索下,毕竟我也用的不多呀。

最后

目前互联网上很多大佬都有 SpringBoot 系列教程,如有雷同,请多多包涵了。本文是作者在电脑前一字一句敲的,每一步都是实践的。若文中有所错误之处,还望提出,谢谢。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Essential PHP Security

Essential PHP Security

Chris Shiflett / O'Reilly Media / 2005-10-13 / USD 29.95

Being highly flexible in building dynamic, database-driven web applications makes the PHP programming language one of the most popular web development tools in use today. It also works beautifully wit......一起来看看 《Essential PHP Security》 这本书的介绍吧!

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具