Spring系列第54篇:集成junit

}

}

2.2、同时运行多个测试用例

可以一个测试类中写多个测试方法,每个方法上加上@Test注解就可以了,然后通过JUnitCore来执行就可以,下面代码中我们写2个方法对MathUtils中的max和min方法都进行测试,我们故意将执行结果和期望结果搞成不一致的,运行下面代码,然后看看运行结果。

package com.javacode2018.junit.demo2;

import com.javacode2018.junit.demo1.MathUtils;

import org.junit.Assert;

import org.junit.Test;

import org.junit.runner.JUnitCore;

import org.junit.runner.Result;

import org.junit.runner.manipulation.Ordering;

import org.junit.runner.notification.Failure;

public class MathUtilsTest2 {

@Test

public void max() throws Exception {

int result = MathUtils.max(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 1);

}

@Test

public void min() throws Exception {

int result = MathUtils.min(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 3);

}

public static void main(String[] args) {

Result result = JUnitCore.runClasses(MathUtilsTest2.class);

System.out.println(“失败用例个数:” + result.getFailures().size());

for (Failure failure : result.getFailures()) {

System.out.println(failure);

}

System.out.println(“运行测试用例个数:” + result.getRunCount());

System.out.println(“运行测试用例总耗时(ms):” + result.getRunTime());

System.out.println(“测试用例是否都成功了:” + result.wasSuccessful());

}

}

运行输出如下,运行了2个用例,失败了2个,测试的详细信息都被输出了

失败用例个数:2

max(com.javacode2018.junit.demo2.MathUtilsTest2): expected:<3> but was:<1>

min(com.javacode2018.junit.demo2.MathUtilsTest2): expected:<1> but was:<3>

运行测试用例个数:2

运行测试用例总耗时(ms):11

测试用例是否都成功了:false

2.3、使用断言

什么是断言?

断言是用来判断程序的运行结果和我们期望的结果是不是一致的,如果不一致,会抛出异常,断言中有3个信息比较关键

1、被测试的数据

2、期望的数据

3、抛出异常

断言提供的方法将被测试的数据和期望的数据进行对比,如果不一样的时候,将抛出异常,程序可以捕获这个异常,这样就可以知道测试失败了。

junit中的org.junit.Assert类中提供了大量静态方法,用来判断被测试的数据和期望的数据是否一致,不一致,将抛出异常,这里随便列几个大家看一下吧

//判断condition如果不是true,将抛出异常,异常的提示信息是message

public static void assertTrue(String message, boolean condition)

//判断expected和actual是否相等,如果不相等,将抛出异常

public static void assertEquals(Object expected, Object actual)

用法,如:

int result = MathUtils.max(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 1);

2.4、测试套件:批量运行测试用例

到目前为止,我们还只能一次运行一个测试类,如下

JUnitCore.runClasses(MathUtilsTest2.class)

但是在实际项目中,我们可能会有很多测试类,需要批量运行。

比如我们有下面2个测试类

MathUtilsTest3001.java

package com.javacode2018.junit.demo3;

import com.javacode2018.junit.demo1.MathUtils;

import org.junit.Assert;

import org.junit.Test;

public class MathUtilsTest3001 {

@Test

public void max() throws Exception {

int result = MathUtils.max(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 3);

}

@Test

public void min() throws Exception {

int result = MathUtils.min(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 1);

}

}

MathUtilsTest3002.java

package com.javacode2018.junit.demo3;

import com.javacode2018.junit.demo1.MathUtils;

import org.junit.Assert;

import org.junit.Test;

import org.junit.runner.JUnitCore;

import org.junit.runner.Result;

import org.junit.runner.notification.Failure;

public class MathUtilsTest3002 {

@Test

public void max() throws Exception {

int result = MathUtils.max(100, 99, 200);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 200);

}

@Test

public void min() throws Exception {

int result = MathUtils.min(1, -1, 10);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, -1);

}

}

现在我们希望同时运行上面2个测试类,我们可以这么做,创建一个AllTest.java类,注意这个类上有2个注解比较特殊,都是junit提供的,@RunWith表示这是一个测试套件类,需要批量运行测试类,具体要运行哪些测试类呢,通过@Suite.SuiteClasses来指定

package com.javacode2018.junit.demo3;

import org.junit.runner.RunWith;

import org.junit.runners.Suite;

@RunWith(Suite.class)

@Suite.SuiteClasses({MathUtilsTest3001.class, MathUtilsTest3002.class})

public class AllTest {

}

下面来个启动类,将AllTest传递给JUnitCore.runClasses

package com.javacode2018.junit.demo3;

import com.javacode2018.junit.demo1.MathUtilsTest;

import com.javacode2018.junit.demo2.MathUtilsTest2;

import org.junit.runner.JUnitCore;

import org.junit.runner.Result;

import org.junit.runner.notification.Failure;

public class Demo3TestRunner {

public static void main(String[] args) {

//@1:传入AllTest

Result result = JUnitCore.runClasses(AllTest.class);

System.out.println(“失败用例个数:” + result.getFailures().size());

for (Failure failure : result.getFailures()) {

System.out.println(failure);

}

System.out.println(“运行测试用例个数:” + result.getRunCount());

System.out.println(“运行测试用例总耗时(ms):” + result.getRunTime());

System.out.println(“测试用例是否都成功了:” + result.wasSuccessful());

}

}

运行输出

失败用例个数:0

运行测试用例个数:4

运行测试用例总耗时(ms):12

测试用例是否都成功了:true

测试套件中不仅可以包含基本的测试类,而且可以包含其它的测试套件,这样可以很方便的分层管理不同模块的单元测试代码,比如下面代码,Module2Test和Module2Test都是测试套件

@RunWith(Suite.class)

@Suite.SuiteClasses({Test1.class, Test2.class})

public class Module2Test {

}

@RunWith(Suite.class)

@Suite.SuiteClasses({Test1.class, Test2.class})

public class Module2Test {

}

@RunWith(Suite.class)

@Suite.SuiteClasses({Module2Test.class, Module2Test.class, Test3.java})

public class AllTest {

}

//运行AllTest

JUnitCore.runClasses(AllTest.class);

2.5、Junit常用注解

1)@Test注解

@Test:将一个普通方法修饰成一个测试方法

@Test(excepted=xx.class):xx.class 表示异常类,表示测试的方法抛出此异常时,认为是正常的测试通过的

@Test(timeout = 毫秒数):测试方法执行时间是否符合预期

2)@BeforeClass

会在所有的方法执行前被执行,static 方法 (全局只会执行一次,而且是第一个运行)

3)@AfterClass

会在所有的方法执行之后进行执行,static 方法 (全局只会执行一次,而且是最后一个运行)

4)@Before

会在每一个测试方法被运行前执行一次

5)@After

会在每一个测试方法运行后被执行一次

6)@Ignore

所修饰的测试方法会被测试运行器忽略

7)@RunWith

可以更改测试运行器 org.junit.runner.Runner

下面的案例,基本上用到了上面所有的注解,大家结合输出理解一下。

package com.javacode2018.junit.demo4;

import com.javacode2018.junit.demo1.MathUtils;

import org.junit.*;

import org.junit.runner.JUnitCore;

import org.junit.runner.Result;

import org.junit.runner.notification.Failure;

import java.util.concurrent.TimeUnit;

public class MathUtilsTest4 {

@BeforeClass

public static void bc() {

System.out.println(“@BeforeClass”);

System.out.println(“-----------------”);

}

@AfterClass

public static void ac() {

System.out.println(“@AfterClass”);

}

@Before

public void bf() {

System.out.println(“@Before:” + this);

}

@After

public void af() {

System.out.println(“@After:” + this);

System.out.println(“##################”);

}

@Test

public void max() throws Throwable {

System.out.println(“max():” + this);

int result = MathUtils.max(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 3);

}

@Test

public void min() throws Exception {

System.out.println(“min():” + this);

int result = MathUtils.min(1, 2, 3);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(result, 1);

}

//方法运行时间超过了timeout,表示测试用例运行失败

@Test(timeout = 1000)

public void timeOutTest() throws InterruptedException {

System.out.println(“timeOutTest():” + this);

TimeUnit.SECONDS.sleep(2000);

}

//方法若未抛出expected指定的异常,表示测试用例运行失败

@Test(expected = NullPointerException.class)

public void expectedTest() {

System.out.println(“expectedTest():” + this);

new RuntimeException(“异常不匹配”);

}

@Test

@Ignore

public void ignoredMethod() {

System.out.println(“我是被忽略的方法”);

}

public static void main(String[] args) {

Result result = JUnitCore.runClasses(MathUtilsTest4.class);

System.out.println(“-----------------”);

System.out.println(“运行测试用例个数:” + result.getRunCount());

System.out.println(“失败用例个数:” + result.getFailures().size());

for (Failure failure : result.getFailures()) {

System.out.println(failure);

}

System.out.println(“运行测试用例总耗时(ms):” + result.getRunTime());

System.out.println(“测试用例是否都成功了:” + result.wasSuccessful());

}

}

运行结果如下

@BeforeClass


@Before:com.javacode2018.junit.demo4.MathUtilsTest4@78e03bb5

timeOutTest():com.javacode2018.junit.demo4.MathUtilsTest4@78e03bb5

@After:com.javacode2018.junit.demo4.MathUtilsTest4@78e03bb5

##################

@Before:com.javacode2018.junit.demo4.MathUtilsTest4@48533e64

max():com.javacode2018.junit.demo4.MathUtilsTest4@48533e64

@After:com.javacode2018.junit.demo4.MathUtilsTest4@48533e64

##################

@Before:com.javacode2018.junit.demo4.MathUtilsTest4@7e0b37bc

min():com.javacode2018.junit.demo4.MathUtilsTest4@7e0b37bc

@After:com.javacode2018.junit.demo4.MathUtilsTest4@7e0b37bc

##################

@Before:com.javacode2018.junit.demo4.MathUtilsTest4@1a93a7ca

expectedTest():com.javacode2018.junit.demo4.MathUtilsTest4@1a93a7ca

@After:com.javacode2018.junit.demo4.MathUtilsTest4@1a93a7ca

##################

@AfterClass


运行测试用例个数:4

失败用例个数:3

timeOutTest(com.javacode2018.junit.demo4.MathUtilsTest4): test timed out after 1000 milliseconds

max(com.javacode2018.junit.demo4.MathUtilsTest4): hah

expectedTest(com.javacode2018.junit.demo4.MathUtilsTest4): Expected exception: java.lang.NullPointerException

运行测试用例总耗时(ms):1018

测试用例是否都成功了:false

从输出中可以看出

  • @BeforeClass和@AfterClass标注的方法只会运行一次

  • 每个@Test标注的方法运行之前会先运行@Before标注的方法,然后运行@Test标注的这个方法,之后再运行@After

  • 从this的输出看出,每个@Test运行的时候,当前类的实例都会重新创建一个新的

  • 不论@Test标注的方法是否异常,@AfterClass、@After标注的方法都会执行,且异常会被淹没,输出中看不到异常信息

2.6、参数化测试

Junit 4 引入了一个新的功能参数化测试

参数化测试允许开发人员使用不同的值反复运行同一个测试,你将遵循 5 个步骤来创建参数化测试

  • 用 @RunWith(Parameterized.class) 来注释 test 类。

  • 创建一个由 @Parameters 注释的公共的静态方法,它返回一个对象的集合(数组)来作为测试数据集合。

  • 创建一个公共的构造函数,它接受和一行测试数据相等同的东西。

  • 为每一列测试数据创建一个实例变量。

  • 用实例变量作为测试数据的来源来创建你的测试用例。

可能大家看了上面的理解,还是比较迷糊。

比如我们com.javacode2018.junit.demo1.MathUtils#max测试下面几组数组

1,2,3

100,99,80

30,-1,100

我们可以这么写

package com.javacode2018.junit.demo5;

import com.javacode2018.junit.demo1.MathUtils;

import org.junit.Assert;

import org.junit.Test;

import org.junit.runner.JUnitCore;

import org.junit.runner.Result;

import org.junit.runner.RunWith;

import org.junit.runner.notification.Failure;

import org.junit.runners.Parameterized;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

@RunWith(Parameterized.class)

public class MathUtilsTest5 {

public static class TestData {

int[] testData;//测试数据

int expectedValue;//预期的结果

public TestData(int[] testData, int expectedValue) {

this.testData = testData;

this.expectedValue = expectedValue;

}

@Override

public String toString() {

return “TestData{” +

“testData=” + Arrays.toString(testData) +

“, expectedValue=” + expectedValue +

‘}’;

}

}

private TestData testData;

@Parameterized.Parameters

public static List initTestData() {

System.out.println(“initTestData()”);

//key:期望的结果,value:max方法需要测试的数据

List result = new ArrayList<>();

result.add(new TestData(new int[]{1, 2, 3}, 3));

result.add(new TestData(new int[]{100, 99, 80}, 100));

result.add(new TestData(new int[]{30, -1, 100}, 100));

return result;

}

public MathUtilsTest5(TestData testData) {

System.out.println(“MathUtilsTest5构造器:” + testData);

this.testData = testData;

}

@Test

public void maxTest() throws Throwable {

System.out.println(this.hashCode() + “,maxTest():” + this.testData);

int result = MathUtils.max(this.testData.testData);

//判断测试结果和我们期望的结果是否一致

Assert.assertEquals(this.testData.expectedValue, result);

System.out.println(“###################”);

}

public static void main(String[] args) {

Result result = JUnitCore.runClasses(MathUtilsTest5.class);

System.out.println(“-----------------”);

System.out.println(“运行测试用例个数:” + result.getRunCount());

System.out.println(“失败用例个数:” + result.getFailures().size());

for (Failure failure : result.getFailures()) {

System.out.println(failure);

}

System.out.println(“运行测试用例总耗时(ms):” + result.getRunTime());

System.out.println(“测试用例是否都成功了:” + result.wasSuccessful());

}

}

为了方便大家理解代码的运行过程,代码中添加了很多日志输出,运行结果如下,结合代码和输出,理解很容易

initTestData()

MathUtilsTest5构造器:TestData{testData=[1, 2, 3], expectedValue=3}

721748895,maxTest():TestData{testData=[1, 2, 3], expectedValue=3}

###################

MathUtilsTest5构造器:TestData{testData=[100, 99, 80], expectedValue=100}

463345942,maxTest():TestData{testData=[100, 99, 80], expectedValue=100}

###################

MathUtilsTest5构造器:TestData{testData=[30, -1, 100], expectedValue=100}

195600860,maxTest():TestData{testData=[30, -1, 100], expectedValue=100}

###################


运行测试用例个数:3

失败用例个数:0

运行测试用例总耗时(ms):12

测试用例是否都成功了:true

3、Spring集成junit


spring集成junit比较简单,下面我们来个案例感受一下。

3.1、加入maven配置

org.springframework

spring-test

5.2.6.RELEASE

junit

junit

4.13

3.2、来个spring的入口配置类

package com.javacode2018.springjunit;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class MainConfig {

@Bean

public String name() {

return “路人甲java”;

}

@Bean

public int age() {

return 30;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

现在其实从大厂招聘需求可见,在招聘要求上有高并发经验优先,包括很多朋友之前都是做传统行业或者外包项目,一直在小公司,技术搞的比较简单,没有怎么搞过分布式系统,但是现在互联网公司一般都是做分布式系统。

所以说,如果你想进大厂,想脱离传统行业,这些技术知识都是你必备的,下面自己手打了一份Java并发体系思维导图,希望对你有所帮助。

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

@Configuration

public class MainConfig {

@Bean

public String name() {

return “路人甲java”;

}

@Bean

public int age() {

return 30;

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。[外链图片转存中…(img-C8S9Toxd-1713428882910)]

[外链图片转存中…(img-3PN8fNi9-1713428882911)]

[外链图片转存中…(img-lhuNegqL-1713428882911)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注Java获取)

img

最后

现在其实从大厂招聘需求可见,在招聘要求上有高并发经验优先,包括很多朋友之前都是做传统行业或者外包项目,一直在小公司,技术搞的比较简单,没有怎么搞过分布式系统,但是现在互联网公司一般都是做分布式系统。

所以说,如果你想进大厂,想脱离传统行业,这些技术知识都是你必备的,下面自己手打了一份Java并发体系思维导图,希望对你有所帮助。

[外链图片转存中…(img-ti75TyRr-1713428882911)]

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 27
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值