Junit这种老技术,现在又拿出来说,不为别的,某种程度上来说,更是为了要说明它在项目中的重要性。

凭本人的感觉和经验来说,在项目中完全按标准都写Junit用例覆盖大部分业务代码的,应该不会超过一半。

刚好前段时间写了一些关于SpringBoot的帖子,正好现在把Junit再拿出来从几个方面再说一下,也算是给一些新手参考了。

那么先简单说一下为什么要写测试用例

1. 可以避免测试点的遗漏,为了更好的进行测试,可以提高测试效率

2. 可以自动测试,可以在项目打包前进行测试校验

3. 可以及时发现因为修改代码导致新的问题的出现,并及时解决

那么本文从以下几点来说明怎么使用Junit,Junit4比3要方便很多,细节大家可以自己了解下,主要就是版本4中对方法命名格式不再有要求,不再需要继承TestCase,一切都基于注解实现。

1、SpringBoot Web项目中中如何使用Junit

创建一个普通的Java类,在Junit4中不再需要继承TestCase类了。

因为我们是Web项目,所以在创建的Java类中添加注解:

@RunWith(SpringJUnit4ClassRunner.class) // SpringJUnit支持,由此引入Spring-Test框架支持!
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class) // 指定我们SpringBoot工程的Application启动类
@WebAppConfiguration // 由于是Web项目,Junit需要模拟ServletContext,因此我们需要给我们的测试类加上@WebAppConfiguration。

接下来就可以编写测试方法了,测试方法使用@Test注解标注即可。

在该类中我们可以像平常开发一样,直接@Autowired来注入我们要测试的类实例。

下面是完整代码:

package org.springboot.sample;

import static org.junit.Assert.assertArrayEquals;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springboot.sample.service.StudentService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration; /**
*
* @author 单红宇(365384722)
* @create 2016年2月23日
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
@WebAppConfiguration
public class StudentTest { @Autowired
private StudentService studentService; @Test
public void likeName() {
assertArrayEquals(
new Object[]{
studentService.likeName("小明2").size() > 0,
studentService.likeName("坏").size() > 0,
studentService.likeName("莉莉").size() > 0
},
new Object[]{
true,
false,
true
}
);
// assertTrue(studentService.likeName("小明2").size() > 0);
} }

接下来,你需要新增无数个测试类,编写无数个测试方法来保障我们开发完的程序的有效性。

2、Junit基本注解介绍

//在所有测试方法前执行一次,一般在其中写上整体初始化的代码
@BeforeClass //在所有测试方法后执行一次,一般在其中写上销毁和释放资源的代码
@AfterClass //在每个测试方法前执行,一般用来初始化方法(比如我们在测试别的方法时,类中与其他测试方法共享的值已经被改变,为了保证测试结果的有效性,我们会在@Before注解的方法中重置数据)
@Before //在每个测试方法后执行,在方法执行完成后要做的事情
@After // 测试方法执行超过1000毫秒后算超时,测试将失败
@Test(timeout = 1000) // 测试方法期望得到的异常类,如果方法执行没有抛出指定的异常,则测试失败
@Test(expected = Exception.class) // 执行测试时将忽略掉此方法,如果用于修饰类,则忽略整个类
@Ignore(“not ready yet”)
@Test @RunWith

在JUnit中有很多个Runner,他们负责调用你的测试代码,每一个Runner都有各自的特殊功能,你要根据需要选择不同的Runner来运行你的测试代码。

如果我们只是简单的做普通Java测试,不涉及spring Web项目,你可以省略@RunWith注解,这样系统会自动使用默认Runner来运行你的代码。

3、参数化测试

Junit为我们提供的参数化测试需要使用 @RunWith(Parameterized.class)

然而因为Junit 使用@RunWith指定一个Runner,在我们更多情况下需要使用@RunWith(SpringJUnit4ClassRunner.class)来测试我们的Spring工程方法,所以我们使用assertArrayEquals 来对方法进行多种可能性测试便可。

下面是关于参数化测试的一个简单例子:

package org.springboot.sample;

import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.Collection; import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class)
public class ParameterTest { private String name;
private boolean result; /**
* 该构造方法的参数与下面@Parameters注解的方法中的Object数组中值的顺序对应
* @param name
* @param result
*/
public ParameterTest(String name, boolean result) {
super();
this.name = name;
this.result = result;
} @Test
public void test() {
assertTrue(name.contains("小") == result);
} /**
* 该方法返回Collection
*
* @return
* @author SHANHY
* @create 2016年2月26日
*/
@Parameters
public static Collection<?> data(){
// Object 数组中值的顺序注意要和上面的构造方法ParameterTest的参数对应
return Arrays.asList(new Object[][]{
{"小明2", true},
{"坏", false},
{"莉莉", false},
});
}
}

4、打包测试

正常情况下我们写了5个测试类,我们需要一个一个执行。

打包测试,就是新增一个类,然后将我们写好的其他测试类配置在一起,然后直接运行这个类就达到同时运行其他几个测试的目的。

代码如下:

@RunWith(Suite.class)
@SuiteClasses({ATest.class, BTest.class, CTest.class})
public class ABCSuite {
// 类中不需要编写代码
}

5、使用Junit测试HTTP的API接口

我们可以直接使用这个来测试我们的Rest API,如果内部单元测试要求不是很严格,我们保证对外的API进行完全测试即可,因为API会调用内部的很多方法,姑且把它当做是整合测试吧。

下面是一个简单的例子:

package org.springboot.sample;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue; import java.util.regex.Matcher;
import java.util.regex.Pattern; import org.hamcrest.Matchers;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.boot.test.WebIntegrationTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate; /**
*
* @author 单红宇(365384722)
* @create 2016年2月23日
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
//@WebAppConfiguration // 使用@WebIntegrationTest注解需要将@WebAppConfiguration注释掉
@WebIntegrationTest("server.port:0")// 使用0表示端口号随机,也可以具体指定如8888这样的固定端口
public class HelloControllerTest { private String dateReg;
private Pattern pattern;
private RestTemplate template = new TestRestTemplate();
@Value("${local.server.port}")// 注入端口号
private int port; @Test
public void test3(){
String url = "http://localhost:"+port+"/myspringboot/hello/info";
MultiValueMap<String, Object> map = new LinkedMultiValueMap<String, Object>();
map.add("name", "Tom");
map.add("name1", "Lily");
String result = template.postForObject(url, map, String.class);
System.out.println(result);
assertNotNull(result);
assertThat(result, Matchers.containsString("Tom"));
} }

6、捕获输出

使用 OutputCapture 来捕获指定方法开始执行以后的所有输出,包括System.out输出和Log日志。

OutputCapture 需要使用@Rule注解,并且实例化的对象需要使用public修饰,如下代码:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SpringBootSampleApplication.class)
//@WebAppConfiguration // 使用@WebIntegrationTest注解需要将@WebAppConfiguration注释掉
@WebIntegrationTest("server.port:0")// 使用0表示端口号随机,也可以具体指定如8888这样的固定端口
public class HelloControllerTest { @Value("${local.server.port}")// 注入端口号
private int port; private static final Logger logger = LoggerFactory.getLogger(StudentController.class); @Rule
// 这里注意,使用@Rule注解必须要用public
public OutputCapture capture = new OutputCapture(); @Test
public void test4(){
System.out.println("HelloWorld");
logger.info("logo日志也会被capture捕获测试输出");
assertThat(capture.toString(), Matchers.containsString("World"));
}
}

关于Assert类中的一些断言方法,都很简单,本文不再赘述。

但是在新版的Junit中,assertEquals 方法已经被废弃,它建议我们使用assertArrayEquals,旨在让我们测试一个方法的时候多传几种参数进行多种可能性测试。

Juit的更多相关文章

  1. 如何在eclipse中通过Juit进行单元测试

    1.什么是Junit Junit即单元测试,是JAVA语言的单元测试框架,是对程序的一个方法所进行的测试 一般都是由程序员自己通过Junit来进行测试,因此单元测试也叫程序员测试: 如果测试人员熟悉程 ...

  2. juit测试中报错:org.hibernate.HibernateException: Unable to get the default Bean Validation factory

    org.hibernate.HibernateException: Unable to get the default Bean Validation factory 解决方法: 解决方案: 在hib ...

  3. JUit——(三)JUnit核心对象(测试、测试类、Suit和Runner)

    JUnit的核心对象:测试.测试类.测试集(Suite).测试运行器 1. 测试: @Test注释的.公共的.不带有任何参数.并且返回void类型的方法 2. 测试类: 公共的,包含对应类的测试方法的 ...

  4. 复习整理2:juit

    @FixMethodOrder(MethodSorters.NAME_ASCENDING)测试回环 https://blog.csdn.net/u014294166/article/details/5 ...

  5. Log4J日志配置与Juit测试

    一.Log4j简介 Log4j有三个主要的组件:Loggers(记录器).Appenders(输出源)和Layouts(布局). 这里可简单理解为日志类别,日志要输出的地方和日志以何种形式输出.综合使 ...

  6. 【Java EE 学习 44】【Hibernate学习第一天】【Hibernate对单表的CRUD操作】

    一.Hibernate简介 1.hibernate是对jdbc的二次开发 2.jdbc没有缓存机制,但是hibernate有. 3.hibernate的有点和缺点 (1)优点:有缓存,而且是二级缓存: ...

  7. Android test---JUnit

    JUnit 单元测试 Android的单元测试基础也是比较简单,同样还是测试相加方法是否正确,测试用例还是用1+1?=2来个简单的Android单元测试: 1..打开eclipse,新建一个proje ...

  8. [翻译]Spring框架参考文档(V4.3.3)-第二章Spring框架介绍 2.1 2.2 翻译--2.3待继续

    英文链接:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html/overview.ht ...

  9. Maven学习(五)-- 聚合与继承

    标签(空格分隔): 学习笔记 Maven的聚合特性能够把项目的各个模块聚合在一起构建: Maven的继承特性能够帮助抽取各模块相同的依赖和插件等配置,在简化POM的同时,还能够促进各个模块配置的一致性 ...

随机推荐

  1. python:python2与python3共存时,pip冲突,提示Fatal error in launcher: Unable to create process using '"d:\python27\python2.exe" "D:\Python27\Scripts\pip2.exe" '

    问题背景: 机器上同时装了python2.和python3后,导致只能用pip3了,使用pip2时提示:Fatal error in launcher: Unable to create proces ...

  2. AWS 核心服务概述(二)

    目录 AWS网络服务 VPC Direct Connect Route53 AWS 计算服务 EC2 EMR(Elastic MapReduce) AWS Lambda Auto Scaling El ...

  3. 粒子系统与雨的效果 (DirectX11 with Windows SDK)

    前言 最近在学粒子系统,看这之前的<<3D图形编程基础 基于DirectX 11 >>是基于Direct SDK的,而DXSDK微软已经很久没有更新过了并且我学的DX11是用W ...

  4. leetcode1105 Filling Bookcase Shelves

    思路: dp[i]表示摆放好前i本书所需要的最小代价. 实现: class Solution { public: int minHeightShelves(vector<vector<in ...

  5. OpenGL学习笔记 之一 (基本的图形绘制)

    参考网址:http://www.cnblogs.com/FredCong/archive/2012/10/13/2722893.html #include <glut.h> #includ ...

  6. 最新 梦网科技java校招面经 (含整理过的面试题大全)

    从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.梦网科技等10家互联网公司的校招Offer,因为某些自身原因最终选择了梦网科技.6.7月主要是做系统复习.项目复盘.Leet ...

  7. 国产龙芯服务器源码安装PostgreSQL数据库的方法

    1. 公司最近有一些国产化项目的需求, 要求在国产CPU的服务器上面安装pg数据库等. 2.. 但是差查了下中标麒麟的官网,在龙芯MIPS的操作系统包源里面仅有 postgreSQL 9.2 版本的r ...

  8. time模块/datetime模块/calendar模块

    time模块时间的表示形式时间戳:以整型或浮点型表示⼀个时间,该时间以秒为单位,这个时间是以1970年1⽉1⽇0时0分0秒开始计算的. 导入time import time 1.返回当前的时间戳 no ...

  9. WUSTOJ 1241: 到底是几月几日?(Java)

    1241: 到底是几月几日? 题目   输入年月日,输出当前日期是当年的第几天,输入年份和第几天,输出当前日期.更多内容点击标题. 说明   算是水题吧,仅提供代码做参考,不做分析.代码没用JDK自带 ...

  10. QLineEdit的信号函数

    QLineEdit一共有6个信号函数,并不多,很好理解. ·void cursorPositionChanged( intold, intnew ) 当鼠标移动时发出此信号,old为先前的位置,new ...