junit系列笔记

本文详细介绍了软件测试的基础知识,包括测试的概念、流程和分类。接着重点讲解了JUnit的使用,从基本的入门实例到JUnit3.x与JUnit4.x的区别,再到断言的原理和应用。最后探讨了JUnit的高级特性,如@RunWith注解的三种用法:Suite.class、Parameterized.class和Theories.class,展示了如何更高效地组织和运行测试用例。

1.基本概念的讲解

1.1 什么是软件测试:
	1)软件测试是通过考虑软件的所有属性(可靠性,可伸缩性,可移植性,可重用性,可用性)和评估软件组件的执行来查找软件错误或错误或缺陷来识别软件正确性的过程。

	2)软件测试提供了软件的独立视图和目标,并确保软件的适用性。它涉及在所需服务下测试所有组件,以确认它是否满足指定的要求。该过程还向客户提供有关软件质量的信息。

	3)测试是强制性的,因为如果软件由于缺乏测试而导致任何时间失败将是一种危险的情况。因此,没有测试软件就无法部署到最终用户。

	4)测试是一组用于在预定义脚本下确定应用程序正确性的技术,但是,测试无法找到应用程序的所有缺陷。测试的主要目的是检测应用程序的故障,以便发现和纠正故障。它并未证明产品在所有条件下都能正常运行,但仅表明它在某些特定条件下无法正常工作。

	5)测试提供了比较软件的行为和状态与机制的比较,因为该机制可以识别问题。该机制可以包括相同指定产品的过去版本,可比较产品,以及预期目的,相关标准或其他标准的界面,但不限于这些。

	6)测试包括检查代码以及各种环境中的代码执行,条件以及代码的所有检查方面。在当前的软件开发方案中,测试团队可能与开发团队分开,以便从测试中获得的信息可用于纠正软件开发过程

	7)软件是否成功取决于对目标受众的接受,简单的图形用户界面,强大的功能负载测试等。例如,银行业务的受众与视频游戏的受众完全不同。因此,当企业在开发软件产品时,它可以评估软件产品是否对其购买者和其他受众有益。

ps:小结:软件测试:就是运用一系列的手段和措施(测试工具软件和测试代码)尽可能的找出bug,确保和提升软件产品的质量,改善用户的体验度。

1.2 软件测试的流程是怎样的/软件测试的生命周期
     1. 需求分析:在此阶段,测试人员分析软件开发的需求文档,以检查客户所述的要求(先要掌握客户要做的是什么样的东西)
     2.测试计划:测试人员确定整个项目的估计工作量和成本。此阶段在成功完成需求分析阶段后进行。此阶段提供的测试策略和工作量估算文档。成功完成测试计划创建后,可以开始测试用例执行(测试人员把整个项目的测试计划给制定好)
     3.环境设置:环境设置需要一组必要的软件和硬件来创建测试环境。测试团队不参与设置测试环境,而是创建测试环境的高级开发人员完成(配置硬件环境和软件环境)
     4.测试用例:在此阶段,测试团队启动案例开发和执行活动。测试团队记下详细的测试用例,并在需要时准备测试数据(至于怎么编写测试用例,这个可以根据具体的情况而定,例如。。。。。)
     5.缺陷记录:此阶段确定了软件的特性和缺点,并作出记录且提交给开发组作出修复,然后就是周期性的交互,直到项目上线。
1.3 软件测试的分类:
    3.1黑盒测试:黑盒测试是一种软件测试技术,它可以检查软件的功能,而不会窥视其内部结构或编码
    3.2白盒测试:需要写代码。关注的是程序的执行流程。
    ps:从是否能看到内部代码的角度看的话,测试分为黑盒测试,白盒测试
    3.3手动测试:需要手动执行测试用例而不是使用自动化工具。测试人员根据最终用户的角度手动执行所有测试用例。它确保应用程序是否正如需求文档中所述那样工作。计划和实施测试用例以完成几乎100%的软件应用程序。测试用例报告也是手动生成的
    3.4自动(化)测试:使用自动化测试工具执行测试用例套件时,称为自动化测试
    ps:从实现的角度看,测试分为手动测试,自动测试
    3.5单元测试:单元测试涉及测试软件应用程序的每个单元或单个组件。这是第一级软件测试。单元测试的目的是验证单元组件的性能(我们今天讲的Junit主要就是进行单元测试的)
    3.6集成测试是单元测试后软件测试过程的第二个层次。在此测试中,软件的单元或单个组件在组中进行测试
    ps:从模块的大小划分角度看:测试分为单元测试,集成测试

2.Junit的基本使用

2.1 入门例子

1.利用Junit3.x实现单元测试

package com.rj.bd.t1;
/**
 * @desc   利用Junit3.x实现单元测试
 * @author 56991
 */
import junit.framework.TestCase;

public class JavaTest extends TestCase {
	 protected int value1, value2;//定义两个由protected修饰的整形变量
	 
	 /**
	  * @desc  1.在所有测试调用指令发起前(在testAdd()方法之前执行,名字不能更改,否则无效)
	  */
	 protected void setUp(){
		 System.out.println("在执行testAdd()方法之前的准备,即为value1和value2赋值");
	      value1=3;
	      value2=3;
	   }
	 /**
	  * @desc 2.本次进行单元测试的方法--testAdd(),且方法的名字必须是test开头,不然会出错误:initializationError
	  */
	  public void  testAdd(){
	      double result= value1 + value2;
	      assertTrue(result == 6);//断言:
	   }
	  
	  /**
	   * @desc 3.在测试方法运行后(在testAdd()方法之后执行,名字不能随意更改,否则无效)
	   */
	  public void tearDown()
	  {
		 System.out.println("最后执行");
	  }
}

2.2.利用Junit4.x实现单元测试

package com.rj.bd.t1;

import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;

/**
 * @desc   利用Junit4.x实现单元测试
 * @author 56991
 */
public class JavaTest02 {
	
	protected int value1, value2;
	
	@Before
	public void  init()
	{
	System.out.println("通过@befoe注解实现在执行之前赋值");
	value1=3;
	value2=3;
	}
	
	@Test
	public void  getSum()
	{
	 double result=value1+value2;	
	 Assert.assertTrue(result == 6);//断言:
	}
	
	@After
	public void end()
	{
     System.out.println("通过@After注解实现在执行getSum()之后的操作");		
	}
}
2.2 Junit3.x与Junit4.x的区别

1)在JUnit 3.x 中对测试必须继承 TestCase这个父类
2)JUnit 3.x 每个方法名必须以test开头.比如:testMethod1()
3)JUnit3.x 必须要重写TestCase的setUp()方法和tearDown()方法,分别执行初始化和释放资源的操作
4)JUnit 4.x 中使用@Before和@After来标识,方法名可以随意定义如:testMethod1()**
5)JUnit 4.x和普通Java类没有区别,只需加上注解标注即可

2.3 断言

1.什么是断言:
断言在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,断言用于保证程序最基本、最关键的正确性。断言检查通常在开发和测试时开启。为了保证程序的执行效率,在软件发布后断言检查通常是关闭的
ps:断言就是契约式编程的一种体现。
ps:断言不应该以任何方式改变程序的状态。简单的说,如果希望在不满足某些条件时阻止代码的执行,就可以考虑用断言来阻止它

2.java 种的断言:
1)也就是所谓的assertion,是jdk1.4后加入的新功能。
2)它主要使用在代码开发和测试时期,用于对某些关键数据的判断,如果这个关键数据不是你程序所预期的数据,程序就提出警告或退出。
当软件正式发布后,可以取消断言部分的代码。java中使用assert作为断言的一个关键字,这就可以看出java对断言还是很重视的,因为如果不是很重要的话,直接开发个类就可以了,没必要新定义一个关键字
ps:Junit测试框架已经有好大哥已经写好了类和相应的方法了

3.断言的语法:
1)语法1:assert expression; //expression代表一个布尔类型的表达式,如果为真,就继续正常运行,如果为假,程序退出

2)语法2:assert expression1 : expression2; //expression1是一个布尔表达式,expression2是一个基本类型或者Object类型,如果expression1为真,则程序忽略expression2继续运行;如果expression1为假,则运行expression2,然后退出程序

ps:详情见当天的代码

4.断言的使用1

package com.rj.bd.t2;
/**
 * @desc   断言的第一种使用方法
 * @author WYH
 * @time   2021-01-11
 */
public class AssertionDemo {
	public static int i = 5;//定义一个静态整形变量i,且赋初值为5
	public static void main(String[] args) {
		assert i==6;  //断言,判断变量i是否等于6,如果断言起到作用了,那么11行就不执行了
        System.out.println("如果断言正常,我就被打印");
        //ps:为了能演示出效果,我们需要将eclipse识别断言功能(默认是关闭的),怎么打开呢(eclipse打开断言功能.png)
	}

}

5.断言的使用2

package com.rj.bd.t2;
/**
 * @desc   断言语法2
 * @author WYH
 * @time   2021-01-11
 */
public class AssertionDemo2 {

	public static void main(String[] args) {  
        int i = 3;  
        switch (i) {  
        case 1:  
            System.out.println("正常");  
            break;  
        case 2:  
            System.out.println("正常");  
            break;  
        case 5:  
            System.out.println("正常");  
            break;  
        default:  
            assert false:"i的值无效";       //如果i的值不是你想要的,程序就警告退出  
        }  
        System.out.println("如果断言正常,我就被打印");  
    }  

}

6.3.断言与异常的区别

1.断言与异常的区别:
1)异常被捕获后可以不做处理,程序从捕获位置继续执行,断言是无法忽略的,程序在断言失败处立即终止因此断言通常用于调试版本,用来发现程序中的逻辑错误

2)如果发现了逻辑错误(异常),必须修改程序(例如Java中有特定的异常处理机制/手段)

3)使用断言的开销比异常小得多,而且断言可以从发布版中完全去除(项目发布的时候,断言是要移除的)

4)异常处理常用在代码编写中,断言常用于软件功能测试中

ps:小结:异常是指代码的逻辑功能,且是在开发的时候需要用到,断言是针对某一功能进行测试的时候用到的

7.小结:断言功能是用于软件的开发和测试的,也就是说,删去断言的那部分语句后,你程序的结构和运行不应该有任何改变,千万不要把断言当成程序中的一个功能来使用

3.Junit的高级使用

@RunWith注解
1.@RunWith(Suite.class)

导读模块:Suite类是JUnit自带的,意为套件,顾名思义,就是一套东西。通过它,可以把多个相关的测试类看做一个测试套件一起测试
ps:在一个项目中,只写一个测试类是不可能的,我们会写出很多很多个测试类。可是这些测试类必须一个一个的执行,也是比较麻烦的事情。
鉴于此,JUnit为我们提供了打包测试的功能,将所有需要运行的测试类集中起来(@RunWith(Suite.class)),一次性的运行完毕,大大的方便了我们的测试工作
补充:这里的打包测试其实是抽象意义上的

1.先创建一个TestA.java,代码如下:

package com.rj.bd.t4;

import java.sql.SQLException;
import org.junit.Test;

public class TestA {

	   @Test(expected=NullPointerException.class)
	    public void  testList() throws ClassNotFoundException, SQLException
	    {
	    	 System.out.println("TestA类中进行的空指针异常测试");
	    	 String str=null;
	    	 System.out.println(str.toLowerCase());
	    }
}

2.创建TestB.java,代码如下:

package com.rj.bd.t4;
import org.junit.Test;
public class TestB {
	  @Test(expected=ArithmeticException.class)
	    public void  testList() 
	    {
	    	 System.out.println("TestB类中除数为0的异常");
	    	 int a=3/0;
	    }
}

3.创建Test03.java,实现使用@RunWith(Suite.class)

package com.rj.bd.t4;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
/**
 * @RunWith指定了Suite类,说明这个Test03类是一个套件。
 * 通过@Suite.SuiteClasses指定了要执行的测试类,那么
 * 这样的话我们就可以一次性的测试TestA.java和TestB.java
 *
 */
@RunWith(Suite.class)
@Suite.SuiteClasses({ TestA.class, TestB.class})
public class Test03 {
	    @Test
	    public void testPrint() {
	        System.out.println("Test03类中的测试用例是不会执行的");
	    }
     //ps:所以当前的Test03.java这个类内容全部为空既可
}
2.@RunWith(Parameterized.class)

1.Parameterized类:也是JUnit自带的,用于使用多个参数组合多次执行同一个测试用例,那么该怎么使用呢?

2.怎样使用呢:
1)类中要有构造函数
2)有一个public static的方法被@Parameters标注,并且该方法只能返回Iterable类型或数组类型的数据
ps:详情见:TestParameterized.java

package com.rj.bd.t4;

import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
/**
 * Parameterized类也是JUnit自带的,用于使用多个参数组合多次执行同一个测试用例
 * 
 */
@RunWith(Parameterized.class)
public class TestParameterized {

	public int expected;
	public int first;
	public int second;	

	    public TestParameterized(int expected, int firstNumber, int secondNumber) {
	        this.expected = expected;
	        this.first = firstNumber;
	        this.second = secondNumber;
	    }    
	
	    @Parameters
	    public static List<Integer[]> parameters() {
	        return Arrays.asList(new Integer[][]{{3, 1, 2}, {5, 2, 3}, {7, 3, 4}, {9, 4, 5}});
	    }
	    
	    @Test
	    public void testPrint() {
	        String format = "Print ----------: expect=%d, first=%d, second=%d";
	        System.out.println(String.format(format, expected, first, second));
	    }
}

3.第二种写法:
构造函数来初始化数据,其实也可以使用字段注入来代替构造方法,只需稍加改变TestParameterized类即可:
1)用Parameter参数来修饰属性。注意:索引从0开始
2)属性要用public修饰
ps:详情见:TestParameterized.java第二种写法

package com.rj.bd.t4;

import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
/**
 * Parameterized类也是JUnit自带的,用于使用多个参数组合多次执行同一个测试用例
 * 
 */
@RunWith(Parameterized.class)
public class TestParameterized {
	    @Parameter(0)
	    public  int expected;
	    @Parameter(1)
	    public  int first;
	    @Parameter(2)
	    public  int second;	

	
	    @Parameters
	    public static List<Integer[]> parameters() {
	        return Arrays.asList(new Integer[][]{{3, 1, 2}, {5, 2, 3}, {7, 3, 4}, {9, 4, 5}});
	    }
	    
	    @Test
	    public void testPrint() {
	        String format = "Print ----------: expect=%d, first=%d, second=%d";
	        System.out.println(String.format(format, expected, first, second));
	    }
}

3.@RunWith(Theories.class)

1.Theories:提供一组参数的排列组合值作为待测方法的输入参数。同时注意到在使用Theories这个Runner的时候,我们的待测方法可以拥有输入参数,而这在其它的Runner中的测试方法是不行的

第一种写法

package com.rj.bd.t5;
/**
 * @desc   以排列组合的方式给测试案例中传递数据值
 * @author 56991
 */
import org.junit.experimental.theories.DataPoint;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

@RunWith(Theories.class)
public class TestTheories {
	    @DataPoint//本意是数据点,在此的意思为将该数据标记为排列组合的方式传递值给测试案例中的参数
	    public static String nameValue1 = "Tony";
	    @DataPoint
	    public static String nameValue2 = "Jim";
	    @DataPoint
	    public static int ageValue1 = 10;
	    @DataPoint
	    public static int ageValue2 = 20;
	    
	    
	    @Theory//本意是推测,在此处的作用是以排列组合的方法给当前的测试用例传递参数
	    public void testMethod(String name, int age){
	        System.out.println(String.format("%s's age is %s", name, age));
	    } 
	    
	    //ps:”Tony”、”Jim”、10、20四个参数以类型合法的排列组合传给待测方法。
	   //因此输出的结果必然也有2x2=4种
}

第二种写法

package com.rj.bd.t5;
/**
 * @desc   以排列组合的方式给测试案例中传递数据值
 * @author 56991
 */
import org.junit.experimental.theories.DataPoints;
import org.junit.experimental.theories.Theories;
import org.junit.experimental.theories.Theory;
import org.junit.runner.RunWith;

@RunWith(Theories.class)
public class TestTheories {
	   //本意是数据点,在此的意思为将该数据标记为排列组合的方式传递值给测试案例中的参数
	    @DataPoints//将相同的数据归为一类写在一起,然后还是以排列组合的方式给测试案例中传递参数值
	    public static String[] names = {"Tony", "Jim"};
	    @DataPoints
	    public static int[] ageValue1 = {10, 20};
	    
	    @Theory//本意是推测,在此处的作用是以排列组合的方法给当前的测试用例传递参数
	    public void testMethod(String name, int age){
	        System.out.println(String.format("%s's age is %s", name, age));
	    } 
	    
	    //ps:”Tony”、”Jim”、10、20四个参数以类型合法的排列组合传给待测方法。
	   //因此输出的结果必然也有2x2=4种
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值