JUnit测试

认识软件测试

在编写程序的过程中,代码完成以后必须进行测试和调试,也就是说程序员要对自己编写的代码负责,既要保证代码的正确编译运行,又要保证与预期结果相符合,这就涉及到单元测试.
软件测试的意义
什么是软件测试呢?测试是发现并指出软件(包括建模、需求分析、设计等阶段产生的各种文档产品)中存在的缺陷的过程。这个过程指出软件中缺陷的确定位置,进行详细记录,并且同时给出与预期的结果偏差。一般软件测试采用人工或利用工具来完成。

测试在软件开发周期中起着至关重要的作用:

  • 测试可以找到软件中存在的缺陷,避免连锁负面反应的发生。
  • 测试不仅为了找到缺陷,更能帮助管理者提升项目管理能力并预防缺陷的发生,改进管理措施。
  • 测试是评定软件质量的一个有效方法。

软件测试的分类
软件测试的经典定义是:在规定的条件下对程序进行操作,以发生程序错误,衡量软件质量,并对其是否能满足设计要求进行评估的过程.
分类
- 单元VS集成测试
- 白盒VS黑盒测试
- 自动VS手动测试
- 回归测试
- 压力测试
单元和集成测试
单元测试(unit testing) 是指对软件中的最小可测试单元进行检查和验证。通常是一个函数/方法。
单元测试是已知代码结构进行的测试,属于白盒测试。
集成测试是将多个单元相互作用,形成一个整体,对整体协调性进行测试。
一般从构成系统的最小单元开始,持续推进到单元之间的接口直到集成为一个完成的软件系统为止。

白盒和黑盒测试
白盒测试(white-box testing),全面 了解程序内部逻辑结构,对所有的逻辑路径都进行测试。一般由程序员完成
黑盒测试(black-box testing),又名功能测试,将程序视为一个不能打开的黑盒子。 在完全不考虑程序内部结构和内部特性的情况下,检查程序功能是否按照需求规格说明书的规定正常使用。一般由独立的使用者完成。

自动和手动测试
自动测试:用程序批量、反复测试程序,并可自动检查程序结果是否满足预定的要求。
手动测试:手动执行程序,手动输入所需要的参数,手动检查程序结果是否满足预定的要求。

回归测试
回归测试:修改旧代码后,重新进行测试以确认修改没有引入新的错误或导致其他代码产生错误。
回归测试在整个软件测试过程中占有很大的比重。软件快速迭代开发过程中,新版本的连续发布(Daily/Nighdy Build)使得回归测试进行的更加频繁。

测试策略

基于main函数的策略
优点:简单
缺点:
无法自动判断被测对象的行为是否符合预期
main方法需要添加大量的代码,这些代码在发布时候也需要手动删除
分散程序员在开发时的关注点
基于自动化测试框架的策略
初始化>输入测试数据执行被测代码->获取系统实际结果>比较
结果是否一致->输出测试结论

JUnit简介

JUnit:一个java语言的单元测试框架

  • Kent Beck(极限编程)和ErichGamma(设计模式)建立的
  • 是xUnit家族中最成功的一个
  • 大部分的java IDE都是集成了JUnit作为单元测试工具
  • 版本
    *5:最后稳定版5.3.2,2018.11发布
    *4:最后稳定版4.12,2014.12发布
    *3:最后稳定版3.8.2,2007.5发布

JUnit注解描述
@Test 测试注解,标记一个方法可以作为一个测试用例 。
@Before Before注解表示,该方法必须在类中的每个测试之前执行,以便执行某些必要的先决条件。
@BeforeClass BeforeClass注解指出这是附着在静态方法必须执行一次并在类的所有测试之前,这种情况一般用于测试计算、共享配制方法(如数据库连接)。
@After After注释表示,该方法在每项测试后执行(如执行每一个测试后重置某些变量,删除临时变量等)。
@AfterClass 当需要执行所有测试在JUnit测试用例类后执行,AlterClass注解可以使用以清理一些资源(如数据库连接),注意:方法必须为静态方法。
@Ignore 当想暂时禁用特定的测试执行可以使用这个注解,每个被注解为@Ignore的方法将不再执行
@Runwith @Runwith就是放在测试类名之前,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器。
@Parameters 用于使用参数化功能。
@SuiteClasses 用于套件测试

JUnit断言
void assertEquals([String message],expected value,actual value) 断言两个值相等。值类型可能是int,short,long,byte,char,Object,第一个参数是一个可选字符串消息
void assertTrue([String message],boolean condition) 断言一个条件为真
void assertFalse([String message],boolean condition) 断言一个条件为假
void assertNotNull([String message],java.lang.Object object) 断言一个对象不为空(null)
void assertNull([String message],java.lang.Object object) 断言一个对象为空(null)
void assertSame([String message],java.lang.Object expected,java.lang.Object actual) 断言两个对象引用相同的对象
void assertNotSame([String message],java.lang.Object unexpected,java.lang.Object actual) 断言两个对象不是引用同一个对象
void assertArrayEquals([String message],expectedArray,resultArray) 断言预期数组和结果数组相等,数组类型可能是int,short,long,byte,char,Object

让我们看下使用断言的例子。

public class AssertionTest {

    @Test
    public void test() {
        String obj1 = "junit";
        String obj2 = "junit";
        String obj3 = "test";
        String obj4 = "test";
        String obj5 = null;
        
        int var1 = 1;
        int var2 = 2;

        int[] array1 = {1, 2, 3};
        int[] array2 = {1, 2, 3};

        Assert.assertEquals(obj1, obj2);

        Assert.assertSame(obj3, obj4);
        Assert.assertNotSame(obj2, obj4);
        
        Assert.assertNotNull(obj1);
        Assert.assertNull(obj5);

        Assert.assertTrue(var1 < var2);
        Assert.assertFalse(var1 > var2);

        Assert.assertArrayEquals(array1, array2);

    }
}

在以上类中我们可以看到,这些断言方法是可以工作的。

assertEquals() 如果比较的两个对象是相等的,此方法将正常返回;否则失败显示在JUnit的窗口测试将中止。
assertSame() 和 assertNotSame() 方法测试两个对象引用指向完全相同的对象。
assertNull() 和 assertNotNull() 方法测试一个变量是否为空或不为空(null)。
assertTrue() 和 assertFalse() 方法测试if条件或变量是true还是false。
assertArrayEquals() 将比较两个数组,如果它们相等,则该方法将继续进行不会发出错误。否则失败将显示在JUnit窗口和中止测试。

我们在这里介绍JUnit4版本因为大多数软件都还是那4来测试
定义一个测试类(测试用例)
建议
测试类名:被测试的类名Test 如CalculationTest
报名:xxx.xxx.xx.test 如cn.itcast.test
定义测试方法:可以独立运行
建议
方法名:test测试的方法名 如testAdd()
返回值:void
参数列表:空参
给方法家@Test
导入junit依赖环境
鉴定结果:
红色:失败
绿色:成功
一般我们会使用断言操作来处理结果
Assert.assertEquals(期望的结果,运算的结果);
补充:JUnit4其他注解的使用

案例

public class JunitTest {

    @BeforeClass
    public static void beforeClass() {
        System.out.println("in before class");
    }

    @AfterClass
    public static void afterClass() {
        System.out.println("in after class");
    }

    @Before
    public void before() {
        System.out.println("in before");
    }

    @After
    public void after() {
        System.out.println("in after");
    }

    @Test
    public void testCase1() {
        System.out.println("in test case 1");
    }

    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }

}

用行结果:

in before class
in before
in test case 1
in after
in before
in test case 2
in after
in after class

注意:一般我们显示结果红色是失败 绿色是成功 为了好理解我就答应出来啦

忽略测试(一般不怎么用 这里理解一下就好)
一个带有@Ignore注解的测试方法不会被执行
如果一个测试类带有@Ignore注解,则它的测试方法将不会被执行
我们把刚才测试类中的testCase2()方法标记为@Ignore,

 @Ignore
    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }

测试结果

in before class
in before
in test case 1
in after

Test ignored.
in after class

异常测试
Junit 用代码处理提供了一个追踪异常的选项。你可以测试代码是否它抛出了想要得到的异常。expected 参数和 @Test 注释一起使用。现在让我们看看 @Test(expected)。新建测试方法testCase3()。

@Test(expected = ArithmeticException.class)
    public void testCase3() {
        System.out.println("in test case 3");
        int a = 0;
        int b = 1 / a;
    }

单独执行testCase3()方法,由于得到了一个预期异常,所以测试通过,结果为

in before class
in before
in test case 3
in after
in after class

如果没有得到预期异常:

in before class
in before
in test case 3
in after

java.lang.AssertionError: Expected exception: java.lang.ArithmeticException

in after class

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

-为准备使用参数化测试的测试类指定特殊的运行器 org.junit.runners.Parameterized。

为测试类声明几个变量,分别用于存放期望值和测试所用数据。
为测试类声明一个带有参数的公共构造函数,并在其中为第二个环节中声明的几个变量赋值。
为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为 java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对。
编写测试方法,使用定义的变量作为参数进行测试。
什么是@RunWith?
首先要分清几个概念:测试方法、测试类、测试集、测试运行器。

其中测试方法就是用@Test注解的一些函数。
测试类是包含一个或多个测试方法的一个**Test.java文件,
测试集是一个suite,可能包含多个测试类。
测试运行器则决定了用什么方式偏好去运行这些测试集/类/方法。
而@Runwith就是放在测试类名之前,用来确定这个类怎么运行的。也可以不标注,会使用默认运行器。常见的运行器有:

@RunWith(Parameterized.class) 参数化运行器,配合@Parameters使用JUnit的参数化功能
@RunWith(Suite.class)
@SuiteClasses({ATest.class,BTest.class,CTest.class})
测试集运行器配合使用测试集功能
@RunWith(JUnit4.class), junit4的默认运行器
@RunWith(JUnit38ClassRunner.class),用于兼容junit3.8的运行器
一些其它运行器具备更多功能。例如@RunWith(SpringJUnit4ClassRunner.class)集成了spring的一些功能

/**
 * 步骤一: 指定定参数运行器
 */
@RunWith(Parameterized.class)//死格式
public class PrimeNumberCheckerTest {

    /**
     * 步骤二:声明变量
     */
    private Integer inputNumber;
    private Boolean expectedResult;
    private PrimeNumberChecker primeNumberChecker;

    /**
     * 步骤三:为测试类声明一个带有参数的公共构造函数,为变量赋值
     */
    public PrimeNumberCheckerTest(Integer inputNumber,
                                  Boolean expectedResult) {
        this.inputNumber = inputNumber;
        this.expectedResult = expectedResult;
    }

    /**
     * 步骤四:为测试类声明一个使用注解 org.junit.runners.Parameterized.Parameters 修饰的,返回值为
     * java.util.Collection 的公共静态方法,并在此方法中初始化所有需要测试的参数对
     *   1)该方法必须由Parameters注解修饰 
          2)该方法必须为public static的 
          3)该方法必须返回Collection类型 
          4)该方法的名字不做要求 
          5)该方法没有参数 
     */
    @Parameters//模拟数据
    public static Collection primeNumbers() {
        return Arrays.asList(new Object[][]{
                {2, true},
                {6, false},
                {19, true},
                {22, false},
                {23, true}
        });//Arrays.asList是把数组转换成集合
    }

    @Before
    public void initialize() {
        primeNumberChecker = new PrimeNumberChecker();
    }

    /**
     * 步骤五:编写测试方法,使用自定义变量进行测试
     */
    @Test
    public void testPrimeNumberChecker() {
        System.out.println("Parameterized Number is : " + inputNumber);
        Assert.assertEquals(expectedResult,
                primeNumberChecker.validate(inputNumber));
    }
}
public class PrimeNumberChecker {

    public Boolean validate(final Integer parimeNumber) {
        for (int i = 2; i < (parimeNumber / 2); i++) {
            if (parimeNumber % i == 0) {
                return false;
            }
        }
        return true;
    }
}

Parameterized Number is : 2
Parameterized Number is : 6
Parameterized Number is : 19
Parameterized Number is : 22
Parameterized Number is : 23

测试套件
JUnit测试框架提供了一种批量运行测试类的方法,称为测试套件.简单地说,测试套件就是几个测试类打包组成一套数据进行测试.

  1. 创建一个空类作为测试套件的入口,保证这个空类使用 public 修饰,而且存在公开的不带有任何参数的构造方法。
  2. 使用注解org.junit.runner.RunWith 和orgjunit.runners. Suite.SuiteClasses 修饰这个空类。
  3. 将org.junit.runners.Suite作为参数传入注解RunWith.以提示了Unit使用套件运行器执行此类。
  4. 将需要放入此测试套件的测试类组成数组作为注解SuiteClasses的参数。
public class JunitTest1 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest1");
    }
}
public class JunitTest2 {

    @Test
    public void printMessage(){
        System.out.println("in JunitTest2");
    }
}
@RunWith(Suite.class)//死格式
@Suite.SuiteClasses({//单个类可以写成Suite.SuiteClasses(JunitTest1.class)
        /**
         * 此处类的配置顺序会影响执行顺序
         */
        JunitTest1.class,
        JunitTest2.class
})
public class JunitSuite {

}

测试结果

in JunitTest1
in JunitTest2

测试套件的源码

源码
Parameters 291
getParametersMethod 方法名
Parameterized 调用getParametersMethod
createRunnersForParameters
createRunnerForTestWithParameters
BlockJUnit4ClassRunnerWithParameters—>createTest

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值