推荐JUnit视频教程:JUnit—Java单元测试必备工具

1.基本理论

1.1 单元测试

单元测试又称模块测试,属于白盒测试,是最小单位的测试。模块分为程序模块和功能模块。功能模块指实现了一个完整功能的模块(单元),一个完整的程序单元具备输入、加工和输出三个环节。而且每个程序单元都应该有正规的规格说明,使之对其输入、加工和输出的关系做出名明确的描述。

JUnit是一个回归测试框架(regression testing framework)。Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。Junit是一套框架,继承TestCase类,就可以用Junit进行自动测试了。

1.2 什么是Junit

①JUnit是用于编写可复用测试集的简单框架,是xUnit的一个子集。xUnit是一套基于测试驱动开发的测试框架,有PythonUnit、CppUnit、JUnit等。

②Junit测试是程序员测试,即所谓白盒测试,因为程序员知道被测试的软件如何(How)完成功能和完成什么样(What)的功能。

③多数Java的开发环境都已经集成了JUnit作为单元测试的工具,比如IDEA,Eclipse等等。

④JUnit官网:Junit

1.3 为什么要使用单元测试

①测试框架可以帮助我们对编写的程序进行有目的地测试,帮助我们最大限度地避免代码中的bug,以保证系统的正确性和稳定性。

②很多人对自己写的代码,测试时就简单写main,然后sysout输出控制台观察结果。这样非常枯燥繁琐,不规范。缺点:测试方法不能一起运行,测试结果要程序猿自己观察才可以判断程序逻辑是否正确。

③JUnit的断言机制,可以直接将我们的预期结果和程序运行的结果进行一个比对,确保对结果的可预知性。

1.4 测试覆盖

评测测试过程中已经执行的代码的多少。

1.5 代码覆盖率

代码的覆盖程度,一种度量方式。针对代码的测试覆盖率有许多种度量方式。

  • 语句覆盖( StatementCoverage ):也称为行覆盖( lin EC overage ) , 段覆盖(segmentcoverage)和基本块覆盖(bASicblockcoverage)。它度量每一个可执行语句是否被执行到了。

  • 判定覆盖(DecisionCoverage):也被称为分支覆盖(branchcoverage),所有边界覆盖(alledgescoverage), 基本路径覆盖( basispathcoverage ), 判定路径覆盖(decisiondecisionpath或DDPtesting)。它度量是否每个 BOOL 型的表达式取值true 和 false 在控制结构中都被测试到了。

  • 条件覆盖(ConDItionCoverage): 它独立的度量每一个子表达式,报告每一个子表达式的结果的 true 或 false。这个度量和判定覆盖(decisioncoverage)相似,但是对控制流更敏感。不过,完全的条件覆盖并不能保证完全的判定覆盖。

  • 路径覆盖(PathCoverage):也称为断言覆盖(prEDIcatecoverage),它度量了是否函数的每一个可能的分支都被执行了。路径覆盖的一个好处是:需要彻底的测试。但有两个缺点:一是,路径是以分支的指数级别增加的,例如:一个函数包含 10个 IF 语句,就有 1024 个路径要测试。如果加入一个 IF 语句,路径数就达到 2048;二是,许多路径不可能与执行的数据无关。

  • 循环覆盖(LOOPCoverage):这个度量报告你是否执行了每个循环体零次、只有一次还是多余一次(连续地)。对于 dowhile循环,循环覆盖报告你是否执行了每个循环体只有一次还是多余一次(连续地)。这个度量的有价值的方面是确定是否对于 while 循环和 for 循环执行了多于一次,这个信息在其它的覆盖率报告中是没有的。

2. IDEA中Junit 4的配置

2.1 环境配置

IDEA中自带JUnit的jar包(hamcrest-core-1.3.jarjunit.jarjunit-4.12.jar):位于安装目录下的lib文件内。即:IntelliJ IDEA 2018.1\lib

IDEA自带一个JUnit插件, 该插件可以运行JUnit测试文件,但无法自动生成JUnit测试代码. 如果需要自动生成测试代码,需要安装JUnitGenerator V2.0 插件。

安装方法:File-->settings-->Plguins-->Browse repositories-->输入JUnit-->选择JUnit Generator V2.0安装,安装好后重启 IDEA,即可使用。

PS: IDEA自带的JUnit插件和JUnitGeneratorV2.0插件都要勾选上,若只勾选JUnit可能导致无法自动生成测试文件,若只勾选JUnitGenerator V2.0可能导致生成的测试文件无法运行

2.2 修改配置

  1. 通过模版生成的测试代码与java类在同一个目录下,与maven项目标准测试目录不匹配。修改方法:
    ${SOURCEPATH}/test/${PACKAGE}/${FILENAME} 修改为${SOURCEPATH}/../test/java/${PACKAGE}/${FILENAME}
    有时候会出现一个提示框,提示选择(general/merge/exixt),选择general就行

    ${SOURCEPATH} 原类的路径,就是你自己写的类
    ${PACKAGE} 原类的包名,java包命名规范就是按照包名一级一级创建的文件夹
    ${filename} 测试类的类名

  2. 修改 Junit4 选项卡中包的申明,把默认的 test 前缀去掉。

  3. 生成的测试文件@since位置Date可能存在乱码,可配置JUnit模板更改日期格式,不影响程序可直接忽略。修改方法:
    第40行:@since <pre>$Date</pre> 修改为
    @since <pre>$today</pre>

3. 简单入门单元测试

娄老师的博客文章中讲了单元测试,我们根据老师的方法来进行简单入门单元测试。

什么是单元测试?单元测试(unit testing),是指对软件中的最小可测试单元进行检查和验证。对于单元测试中单元的含义,一般来说,要根据实际情况去判定其具体含义,如Java里单元指一个类。

编程是智力活动,不是打字,编程前要把干什么、如何干想清楚才能把程序写对、写好。与目前不少同学一说编程就打开编辑器写代码不同,我希望同学们养成一个习惯,当你们想用程序解决问题时,要会写三种码:

  • 伪代码
  • 产品代码
  • 测试代码

伪代码与具体编程语言无关,不要写与具体编程语言语法相关的语句(如用malloc分配内存,这样只能用C语言编程了),伪代码从意图层面来解决问题,最终,伪代码产品代码最自然的、最好的注释。

需求:我们要在一个Calculator类中来实现简单计算器的功能。

3.1 伪代码

设计的伪代码:

    简单计算器:

    加法:返回两个数相加后的结果

    减法:返回两个数相减后的结果

    乘法:返回两个数相乘后的结果

    除法:除数不为0,返回两个数相除后的结果

        除数为0,打印异常信息在程序中出错的位置及原因

    其他 :未完成的模块例如平方、开方等等
    

3.2 产品代码

有了伪代码,用特定语言翻译一下,就是可用的产品代码了。
翻译之后的产品代码Calculator.java

public class Calculator {
    public int add(int x, int y) { //加法
        return x + y;
    }

    public int sub(int x, int y) { //减法
        return x - y;
    }

    public int mul(int x, int y) { //乘法
        return x * y;
    }

    public int div(int x, int y) { //除法
        return x / y;
    }

    public int div2(int x, int y) { //除法  做了异常判断
        try {
            int z = x / y;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return x / y;
    }

    public void loop(int x, int y) { //死循环
        for (; ; )
            x = y;
    }

    public void unCompleted(int x, int y) { //未完成的模块:例如平方、开方等等
        //还在开发中
    }

//    public static void main(String[] args) { // 传统代码测试
//        int a = 8;
//        int b = 2;
//        Calculator calculator = new Calculator();
//        System.out.println(calculator.add(a, b));
//        System.out.println(calculator.sub(a, b));
//        System.out.println(calculator.mul(a, b));
//        System.out.println(calculator.div(a, b));
//        System.out.println(calculator.div2(a,0));
//    }
}

在IDEA中创建项目unitTask01,在src 右键新建java类com.ryanjie.junit01.Calculator,将上述代码写入。

3.3 测试代码

写了产品代码,我们还要写测试代码,证明自己的代码没有问题。

Java编程时,程序员对类实现的测试叫单元测试。类XXXX的单元测试,我们一般写建一个XXXXTest的类。

所以,对于Calculator类,我们写一个CalculatorTest.java的测试模块,代码如下:

public class CalculatorTest {
    public static void main(String[] args) {
        Calculator calculator = new Calculator();

        if (calculator.add(8, 2) == 10) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.sub(8, 2) == 6) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.mul(8, 2) == 16) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }

        if (calculator.div(8, 2) == 4) {
            System.out.println("Test passed!");
        } else {
            System.out.println("Test failed!");
        }
    }
}

这里我们设计了一个测试用例(Test Case),测试用例是为某个特殊目标而编制的一组测试输入、执行条件以及预期结果,以便测试某个程序路径或核实是否满足某个特定需求。这里我们的测试输入8和2的加减乘除四种运算,预期结果分别为10,6,16,4

我们在Calculator类上单击鼠标右键,在弹出的菜单中选择Generate(我们可以看到对应键盘快捷键为Alt+Insert)-> Junit Test -> Junit 4,这时IDEA会自动生成一个test目录并生成CalculatorTest类,我们先删除自动生成的代码,输入刚才写的CalculatorTest.java代码。

在 IDEA中我们把产品代码放在src目录中,把测试代码放在test目录中,在命令行中我们知道要设置SOURCEPATH环境变量,在IDEA中我们右键单击test目录,在弹出的菜单中选择Mark Directory as->Test Sources Root就可以了:(这时test文件夹图标会变绿)

在IDEA中运行结果如下,测试结果符合预期:

3.4 测试代码2 (使用Junit)

在刚才自动生成的test目录下,CalculatorTest.java里代码如下:

public class CalculatorTest {

    @Before
    public void before() throws Exception {
    }

    @After
    public void after() throws Exception {
    }

    /**
     *
     * Method: add(int x, int y)
     *
     */
    @Test
    public void testAdd() throws Exception {
    }

    /**
     *
     * Method: sub(int x, int y)
     *
     */
    @Test
    public void testSub() throws Exception {
    }

    /**
     *
     * Method: mul(int x, int y)
     *
     */
    @Test
    public void testMul() throws Exception {

    }

    /**
     *
     * Method: div(int x, int y)
     *
     */
    @Test
    public void testDiv() throws Exception {
    }

    /**
     *
     * Method: div2(int x, int y)
     *
     */
    @Test
    public void testDiv2() throws Exception {
    }

    /**
     *
     * Method: loop(int x, int y)
     *
     */
    @Test
    public void testLoop() throws Exception {
    }

    /**
     *
     * Method: unCompleted(int x, int y)
     *
     */
    @Test
    public void testUnCompleted() throws Exception {
    }

}  

我们修改CalculatorTest.java测试模块,代码如下:

public class CalculatorTest {
    Calculator calculator;

    @Before
    public void setUp() throws Exception {
        calculator = new Calculator();
    }

    @After
    public void after() throws Exception {
    }

    /**
     *
     * Method: add(int x, int y)
     *
     */
    @Test
    public void testAdd() throws Exception {
        Assert.assertEquals(calculator.add(8,2),10);
    }

    /**
     *
     * Method: sub(int x, int y)
     *
     */
    @Test
    public void testSub() throws Exception {
        Assert.assertEquals(calculator.sub(8,2),6);
    }

    /**
     *
     * Method: mul(int x, int y)
     *
     */
    @Test
    public void testMul() throws Exception {
        Assert.assertEquals(calculator.mul(8,2),16);
    }

    /**
     *
     * Method: div(int x, int y)
     *
     */
    @Test
    public void testDiv() throws Exception {
        Assert.assertEquals(calculator.div(8,2),4);
    }

    /**
     *
     * Method: div2(int x, int y)
     *
     */
    @Ignore
    public void testDiv2() throws Exception {
    }

    /**
     *
     * Method: loop(int x, int y)
     *
     */
    @Ignore
    public void testLoop() throws Exception {
    }

    /**
     *
     * Method: unCompleted(int x, int y)
     *
     */
    @Ignore
    public void testUnCompleted() throws Exception {
    }

}

在IDEA中运行结果如下,测试结果符合预期:

3.5 编辑测试设置

我们可以通过Run ->Edit Configuration或工具栏上的标签来调整我们测试运行配置:

Configuration选项卡,用户可以选择需要运行的测试。例如,您可以从一个类、程序包、测试套件或甚至模式中运行所有的测试。这里的Fork模式让用户在一个单独的进程运行每个测试。

代码覆盖测试:

  • 默认情况下使用自己的测试引擎
  • 覆盖率模式:Tracing会增加消耗,但是测试会更准确

3.6 收集覆盖率

Run ->Run 'MyClassTest' with Coverage或工具栏上的选项运行特定模式的测试。

当覆盖模式运行至少一个测试之后,IDE将会在Project工具窗口显示每个程序包、类的覆盖率数据,同时在Coverage工具窗和编辑器中也会显示。

如果用户添加另一个方法到junit01,并运行覆盖率测junit01,就会发现,没有被测试覆盖到的代码都将高亮显示为红色。覆盖的代码颜色则是绿色。如果一些代码是只覆盖部分,那没将显示为黄色。

本文代码:UnitTask01

Demo002 IDEA中Junit单元测试的使用(初级篇)的更多相关文章

  1. Spring框架中整合JUnit单元测试的方法

    一. 步骤: 1. 拷贝jar包: 1. JUnit-4.9.jar和spring-test-4.2.4.RELEASE.jar ; 2. 替换原来的main函数: 1. 在测试类上使用注解方式替换: ...

  2. Myeclipse中进行JUnit单元测试

    最近学习了在myeclipse中进行单元测试,写点东西总结总结. JUnit单元测试: 测试对象为一个类中的方法. juint不是javase中的部分,所以必须导入jar包,但是myeclipse自带 ...

  3. JUnit单元测试中的setUpBeforeClass()、tearDownAfterClass()、setUp()、tearDown()方法小结

    编写JUnit单元测试的时候,会用到 setUpBeforeClass().tearDownAfterClass().setUp().tearDown()这四个方法,例如用 eclipse新建一个ju ...

  4. SSM项目集成Lucene+IKAnalyzer在Junit单元测试中执行异常

    个人博客 地址:http://www.wenhaofan.com/article/20181108132519 问题描述 在项目运行以及main方法中能够正常运行,但是使用junit单元测试时却报如下 ...

  5. 【Java】eclipse中的JUnit单元测试

    eclipse中的JUnit单元测试 步骤: 选中当前工程 - 右键选择:build path - add libraries - JUnit 4 - 下一步 创建Java类,进行单元测试. 此时的J ...

  6. 在Intellij IDEA中添加JUnit单元测试

    Intellij IDEA中添加JUnit单元测试 目录 Intellij IDEA中添加JUnit单元测试 下载jar包 在Intellij IDEA项目中添加jar包 下载插件并进行设置 创建存放 ...

  7. Junit 单元测试在 intelliJ IDEA 中的安装

    1.为什么使用Junit我们都知道,main 方法是一个程序的入口,通常来说,没有main方法,程序就无法运行.我们经常会写一些class文件(如下图所示),他们并没有自己的main方法.那么我们如何 ...

  8. 在Eclipse中使用JUnit4进行单元测试(初级篇、中级篇、高级篇)

    本文转载自以下 初级篇: http://blog.csdn.net/andycpp/article/details/1327147 中级篇: http://blog.csdn.net/andycpp/ ...

  9. junit单元测试(keeps the bar green to keeps the code clean)

    error是程序错误,failure是测试错误. junit概要: JUnit是由 Erich Gamma (设计模式的创始人)和 Kent Beck (敏捷开发的创始人之一)编写的一个回归测试框架( ...

随机推荐

  1. Mac添加环境变量方法

    一句话总结:找到paths文件编辑一下把要加路径写进去 转载注明出处http://www.cnblogs.com/billyrun/p/8631165.html 1.终端输入命令open /etc 开 ...

  2. stylelint 安装配置

    1.安装 stylelint: npm i stylelint -g npm i stylelint stylelint-config-standard --save-dev 2.在 scripts ...

  3. springboot解决跨域问题

    在启动类里加入corsFilter import org.springframework.boot.SpringApplication; import org.springframework.boot ...

  4. 依赖、耦合、解耦、控制反转(IOC)、依赖注入(DI)

    随着net的深入学习,出现了很多概念性的东西需要理解,现在统一记录一下. 1.依赖:现阶段在任何一个有请求作用的系统,都会出现A类调用B类的情况,这时候A类就依赖于B类,A类和B类存在依赖关系. 2. ...

  5. Java Collection - 001 集合的遍历

    import java.util.ArrayList; import java.util.Iterator; import java.util.List; import com.java.domain ...

  6. 前端-JavaScript1-4——JavaScript之变量

    变量(Variables),和高中代数学习的x.y.z很像,它们不是字母,而是蕴含值的符号. 它和直接量不同,直接量5,就是数字5:直接量”你好”就是字符串“你好”.现在这个变量不一样了,你看见一个a ...

  7. SAS 评分卡开发模型变量统计及输出

    以下代码实现功能: 1.获取10个模型分别使用哪些变量 2.变量所模型使用的次数 3.把上表格输出到EXCEL中 %INCLUDE '00@HEADER.SAS'; %let dir=..\04@Mo ...

  8. 高性能mysql 第六章查询性能优化 总结(上)查询的执行过程

    6  查询性能优化 6.1为什么查询会变慢 这里说明了的查询执行周期,从客户端到服务器端,服务器端解析,优化器生成执行计划,执行(可以细分,大体过程可以通过show profile查看),从服务器端返 ...

  9. Activiti流程设计工具

    在Actitivi工程的src/main/resources新建一个文件夹diagrams 然后右键,创建一个activiti Diagram 取名为helloWorld后finish 中间区域,是我 ...

  10. 第27课 可变参数模板(8)_TupleHelper

    1. TupleHelper的主要功能 (1)打印:由于tuple中的元素是可变参数模板,外部并不知道内部到底是什么数据,有时调试时需要知道其具体值,希望能打印出tuple中所有的元素值. (2)根据 ...