JAVA新测试框架--testng和mockito

测试是检查应用程序的功能的过程是否按要求工作,在开发人员层面进行单元测试,在采取适当措施来测试每一个实体(类或方法)以确保最终产品符合要求。单元测试是非常必要的,这是软件公司向他们的客户提供高质量的软件产品必要前提。

较常用的测试框架是Junit4,这个是老框架,现在的互联网开发公司常用的新框架有testng和mockito两种。
单元测试用例是代码的一部分从而确保代码(方法)的另一部分工作正常。要快速实现这些理想的效果,测试框架是必需的。JUnit对于Java编程语言是完美的单元测试框架。

单元测试可以通过两种方式来完成:

手动测试:

手动执行测试用例,没有任何工具支持称为手动测试。
费时和乏味:由于测试案例是由人力的,所以它是非常缓慢而乏味的执行。
巨大的人力资源的投入:作为测试用例需要手动执行,所以更多的测试都需要手动测试。
较不可靠:手动测试是为测试可能不会被精确地每次执行,因为人为错误导致不可靠。
非可编程:无需编程就可以做,获取信息隐藏复杂的测试

自动测试:

以工具支持,并通过使用自动化工具则称为自动化测试执行测试用例。
快速自动化运行测试用例比人力显著更快。
人力资源的投入较少:测试用例是通过使用自动化工具,所以较少测试者都需要在自动化测试执行。
更可靠:自动化测试在每次运行的时间进行精确的相同操作。
可编程:测试人员可以编写复杂的测试,以带出隐藏的信息。

JUnit是一个Java编程语言编写的单元测试框架。 重要的是在测试驱动开发中,并且是一个家族的统称为xUnit单元测试框架中的一个。

JUnit促进“先测试再编码”,它强调建立测试数据的一段代码可以被测试,先测试再编码实现的想法。这种做法就像是“试了一下,码了一点,测试了一下,代码一点点……”这增加了程序员的工作效率和程序代码的稳定性,减少程序员的压力和花在调试的时间。

而TestNG和mockito是全新的测试体系,在junit4的基础上,很多更加简便的测试框架被开发出来,为什么介绍这两种框架,因为现在的软件开放公司都是利用junit+TestNG+mockito的方式,运用大家的优点来搭建总体的测试体系。不过似乎在功能方面,TestNG可以完全替代Junit的功能,不过Junit作为传统的xunit测试体系,在新出的Junit5测试框架也有很强的性能(在下面会做分析)。

Testng

JUnit让开发人员了解测试的实用性,尤其是在单元测试这一模块上比任何其他测试框架都要简单明了。凭借一个相当简单,务实,严谨的架构,JUnit已经能够“感染”了一大批开发人员。

JUnit缺点:
1.最初的设计,使用于单元测试,现在只用于各种测试。
2.不能依赖测试
3.配置控制欠佳(安装/拆卸)
4.侵入性(强制扩展类,并以某种方式命名方法)
5.静态编程模型(不必要的重新编译)
6.不适合管理复杂项目应用,JUnit复杂项目中测试非常棘手。

而TetsNG是什么样的框架?

TestNG是一个测试框架,其灵感来自JUnit和NUnit(也就是xUnit家族的产品),但引入了一些新的功能,使其功能更强大,使用更方便。

TestNG是一个开源自动化测试框架;TestNG表示下一代(Next Generation的首字母)。 TestNG类似于JUnit(特别是JUnit 4),但它不是JUnit框架的扩展。它的灵感来源于JUnit。它的目的是优于JUnit,尤其是在用于测试集成多类时。 TestNG的创始人是Cedric Beust(塞德里克·博伊斯特)。

TestNG消除了大部分的旧框架的限制,使开发人员能够编写更加灵活和强大的测试。 因为它在很大程度上借鉴了Java注解(JDK5.0引入的)来定义测试,它也可以显示如何使用这个新功能在真实的Java语言生产环境中。

TestNG的特点:

1.注解
2.TestNG使用Java和面向对象的功能
3.支持综合类测试(例如,默认情况下,不用创建一个新的测试每个测试方法的类的实例)
4.独立的编译时测试代码和运行时配置/数据信息
5.灵活的运行时配置
6.主要介绍“测试组”。当编译测试,只要要求TestNG运行所有的“前端”的测试,或“快”,“慢”,“数据库”等
7.支持依赖测试方法,并行测试,负载测试,局部故障
8.灵活的插件API
9.支持多线程测试

TestNG(Next Generation)是一个测试框架,它受到JUnit和NUnit的启发,而引入了许多新的创新功能,如依赖测试,分组概念,使测试更强大,更容易做到。 它旨在涵盖所有类别的测试:单元,功能,端到端,集成等…

如何使用TestNG?

展示如何开始使用TestNG单元测试框架,使用的开发环境依然是Eclipse m.3+maven3+JDK1.8
这里选用TestNG的版本为TestNG 6.10版本

第一步:先去官网或者是ali的maven库中去复制TestNG 6.10的版本,然后将其放在pom中的dependencies标签下。

第二步:安装Eclipse的插件支持,在Eclipse Market中搜索“TestNG for Eclipse”,然后install,重启Eclipse。

第三步:查看是否安装成功,在eclipse的工具栏中,点击file-》new-》other,看到TestNG文件夹,即表示安装插件成功。

第四步:这就可以使用TestNG用于测试组件或者单元了,在想要测试的项目的src/test/java下新建“TestNG class”,这个类就相当于Junit的测试类,在这个类中,去写测试代码,然后右键run as–》选择“TestNG test”就可以测试了。(其实测试方法有两种,接下来就讲)

TestNG的测试方式

第一种直接执行:右键要执行的方法,  点Run As ->TestNG Test

第二种: 通过testng.xml文件来执行. 把要执行的case, 放入testng.xml文件中。 右键点击testng.xml, 点Run As
这个xml文件放在src/test/java里即可

在testng.xml中,可以控制测试用例按顺序执行。 当preserve-order=”true”是,可以保证节点下面的方法是按顺序执行的

断言(ASSERT)的用法

这里介绍一下载TestNG中同样也支持断言Assert,在实际开发中用于检测错误。
如何用断言Assert,断言里面又有什么方法?那个方法较为常用呢?

在经过对其进行一定了解之后,对其作用及用法有了一定的了解,assert()的用法像是一种“契约式编程”,在我的理解中,其表达的意思就是,程序在我的假设条件下,能够正常良好的运作,其实就相当于一个if语句:其本质就是代替if-else,因为如果要用if-else来测的话,整个测试结构就会变得很复杂,可读性也不好,程序结构比较臃肿,用了Assert就好多了。

if(假设成立)
{
     程序正常运行;
}
else
{
      报错&&终止程序!(避免由程序运行引起更大的错误)  
}

如果断言的条件错误,则直接程序报错,可以说是一种保障正确的一种方式,org.testng.Assert 用来校验接口测试的结果,那么它提供哪些方法呢?

提供了以下这些方法:(根据实际情况需要而去测试)

assertTrue 判断是否为true。
assertFalse 判断是否为false。
assertSame 判断引用地址是否相等。
assertNotSame 判断引用地址是否不相等。
assertNull 判断是否为null
assertNotNull 判断是否不为null
assertEquals 判断是否相等,Object类型的对象需要实现hashCode及equals方法,集合类型Collection/Set/Map 中的对象也需要实现hashCode及equals方法,3个double参数时比较好玩,前两个double相等,或者前两个double的差值小于传入的第三个double值,即偏移量小于多少时,认为相等。
assertNotEquals 判断是否不相等
assertEqualsNoOrder 判断忽略顺序是否相等

例子:

StringGenerator类
public class StringGenerator {

    public String generate(){
        return "testng demo!";
    }
}

Test类

public class TestNgDemo {
  @Test
  public void test1() {
      StringGenerator sg=new StringGenerator();
      String content=sg.generate();
      /*
       * testng框架中的Assert断言的作用
       * 
       */
      Assert.assertNotNull(content);//判断是否为空
      Assert.assertEquals(content, "testng demo!");//判断内容是否相等
  }
}

控制台输出内容的部分:

[RemoteTestNG] detected TestNG version 6.10.0
[TestNG] Running:
  C:\Users\Administrator\AppData\Local\Temp\testng-eclipse--46238976\testng-customsuite.xml

PASSED: test1

===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 0
===============================================


===============================================
Default suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

这样就是TestNG测试框架的使用,当然这个测试框架还可以应用在很多方面,比如:
TestNG预期异常测试
TestNG忽略测试
TestNG超时测试
TestNG分组测试
TestNG套件测试
TestNG依赖测试
TestNG参数化测试
TestNG参数测试实例
TestNG + Selenium负载测试
TestNG + Spring集成测试

介绍TestNG的各种测试案例

TestNG和Junit4相对比:

JUnit 4和TestNG都是Java中非常受欢迎的单元测试框架。两种框架在功能上看起来非常相似。 哪一个更好? 在Java项目中应该使用哪个单元测试框架?

下面表中概括了JUnit 4和TestNG之间的功能比较。如下图所示 -

logo

注释支持

注释/注解支持在JUnit 4和TestNG中是非常类似的。
logo

JUnit4和TestNG之间的主要注释差异是:

在JUnit 4中,我们必须声明“@BeforeClass”和“@AfterClass”方法作为静态方法。 TestNG在方法声明中更灵活,它没有这个约束。

3个额外的setUp / tearDown级别:suite和group(@Before / AfterSuite,@Before / After Test,@Before / After Group)。

JUnit 4

@BeforeClass
public static void oneTimeSetUp() {
    // one-time initialization code
    System.out.println("@BeforeClass - oneTimeSetUp");
}

TestNG

@BeforeClass
public void oneTimeSetUp() {
        // one-time initialization code
        System.out.println("@BeforeClass - oneTimeSetUp");
}

在JUnit 4中,注释命名约定有点混乱,例如“Before”,“After”和“Expected”,我们并不真正了解“Before”和“After”之前的内容,以及要测试中的“预期” 方法。TestiNG更容易理解,它使用类似“BeforeMethod”,“AfterMethod”和“ExpectedException”就很明了。

异常测试

“异常测试”是指从单元测试中抛出的异常,此功能在JUnit 4和TestNG中都可实现。

JUnit 4

@Test(expected = ArithmeticException.class)
public void divisionWithException() {
  int i = 1/0;
}

TestNG

@Test(expectedExceptions = ArithmeticException.class)
public void divisionWithException() {
  int i = 1/0;
}

忽略测试

“忽略”表示是否应该忽略单元测试,该功能在JUnit 4和TestNG中均可实现。

JUnit 4

@Ignore("Not Ready to Run")
@Test
public void divisionWithException() {
  System.out.println("Method is not ready yet");
}

TestNG

@Test(enabled=false)
public void divisionWithException() {
  System.out.println("Method is not ready yet");
}

时间测试

“时间测试”表示如果单元测试所花费的时间超过指定的毫秒数,则测试将会终止,并将其标记为失败,此功能在JUnit 4和TestNG中均可实现。

JUnit 4

@Test(timeout = 1000)
public void infinity() {
    while (true);
}

TestNG

@Test(timeOut = 1000)
public void infinity() {
    while (true);
}

套件测试

“套件测试”是指捆绑几个单元测试并一起运行。 此功能在JUnit 4和TestNG中都可实现。 然而,两者都使用非常不同的方法来实现它。

JUnit 4

“@RunWith”和“@Suite”用于运行套件测试。下面的类代码表示在JunitTest5执行之后,单元测试“JunitTest1”和“JunitTest2”一起运行。 所有的声明都是在类内定义的。

@RunWith(Suite.class)
@Suite.SuiteClasses({
        JunitTest1.class,
        JunitTest2.class
})
public class JunitTest5 {
}

TestNG

XML文件用于运行套件测试。以下XML文件表示单元测试“TestNGTest1”和“TestNGTest2”将一起运行。

<suite name="My test suite">
  <test name="testing">
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest1" />
       <class name="com.fsecure.demo.testng.TestNGTest2" />
    </classes>
  </test>
</suite>

TestNG可以做捆绑类测试,也可以捆绑方法测试。 凭借TestNG独特的“分组”概念,每种方法都可以与一个组合相结合,可以根据功能对测试进行分类(分组)。 例如,

下面是一个有四个方法的类,三个组(method1,method2和method3)

@Test(groups="method1")
public void testingMethod1() {
  System.out.println("Method - testingMethod1()");
}

@Test(groups="method2")
public void testingMethod2() {
    System.out.println("Method - testingMethod2()");
}

@Test(groups="method1")
public void testingMethod1_1() {
    System.out.println("Method - testingMethod1_1()");
}

@Test(groups="method4")
public void testingMethod4() {
    System.out.println("Method - testingMethod4()");
}

使用以下XML文件,可以仅使用组“method1”执行单元测试。

<suite name="My test suite">
  <test name="testing">
      <groups>
      <run>
        <include name="method1"/>
      </run>
    </groups>
    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest5_2_0" />
    </classes>
  </test>
</suite>

通过“分组”测试概念,集成测试的可能性是无限制的。 例如,我们只能从所有单元测试类中测试“DatabaseFuntion”分组。

参数化测试

“参数化测试”是指单位测试参数值的变化。 此功能在JUnit 4和TestNG中都实现。 然而,两者都使用非常不同的方法来实现它。

JUnit 4

“@RunWith”和“@Parameter”用于提供单元测试的参数值,@Parameters必须返回List [],参数将作为参数传入类构造函数。

@RunWith(value = Parameterized.class)
public class JunitTest6 {

     private int number;

     public JunitTest6(int number) {
        this.number = number;
     }

     @Parameters
     public static Collection<Object[]> data() {
       Object[][] data = new Object[][] { { 1 }, { 2 }, { 3 }, { 4 } };
       return Arrays.asList(data);
     }

     @Test
     public void pushTest() {
       System.out.println("Parameterized Number is : " + number);
     }
}

这里有很多限制,我们必须遵循“JUnit”的方式来声明参数,并且必须将参数传递给构造函数才能初始化类成员作为测试的参数值。参数类的返回类型为“List []”,数据已被限制为String或用于测试的原始类型值。

TestNG

XML文件或“@DataProvider”用于提供不同参数进行测试。

用于参数化测试的XML文件 -

只有“@Parameters”在需要参数测试的方法中声明,参数化数据将在TestNG的XML配置文件中提供。 通过这样做,我们可以使用不同数据集的单个测试用例,甚至获得不同的结果。 另外,即使是最终用户,QA还是QE都可以在XML文件中提供自己的数据进行测试。

public class TestNGTest6_1_0 {

@Test
@Parameters(value="number")
public void parameterIntTest(int number) {
       System.out.println("Parameterized Number is : " + number);
    }
}

XML文件的内容如下 -

<suite name="My test suite">
  <test name="testing">

    <parameter name="number" value="2"/>

    <classes>
       <class name="com.fsecure.demo.testng.TestNGTest6_0" />
    </classes>
  </test>
</suite>

@DataProvider用于参数化测试

将数据值拉入XML文件可能非常方便,但测试偶尔会需要复杂的类型,这些类型不能被表示为一个字符串或一个原始类型值。 TestNG使用@DataProvider注解来处理这种情况,这有助于将复杂参数类型映射到测试方法。

@DataProvider for Vector,String或Integer作为参数,参考如下代码 -

@Test(dataProvider = "Data-Provider-Function")
    public void parameterIntTest(Class clzz, String[] number) {
       System.out.println("Parameterized Number is : " + number[0]);
       System.out.println("Parameterized Number is : " + number[1]);
    }

    //This function will provide the patameter data
    @DataProvider(name = "Data-Provider-Function")
    public Object[][] parameterIntTestProvider() {
        return new Object[][]{
                   {Vector.class, new String[] {"java.util.AbstractList",
"java.util.AbstractCollection"}},
                   {String.class, new String[] {"1", "2"}},
                   {Integer.class, new String[] {"1", "2"}}
                  };
    }

@DataProvider作为对象的参数

“TestNGTest6_3_0”是一个简单的对象,只需使用get/set方法进行演示。

@Test(dataProvider = "Data-Provider-Function")
public void parameterIntTest(TestNGTest6_3_0 clzz) {
   System.out.println("Parameterized Number is : " + clzz.getMsg());
   System.out.println("Parameterized Number is : " + clzz.getNumber());
}

//This function will provide the patameter data
@DataProvider(name = "Data-Provider-Function")
public Object[][] parameterIntTestProvider() {

    TestNGTest6_3_0 obj = new TestNGTest6_3_0();
    obj.setMsg("Hello");
    obj.setNumber(123);

    return new Object[][]{
               {obj}
    };
}

TestNG的参数化测试非常用户友好和灵活(在XML文件或类内)。 它可以支持许多复杂的数据类型作为参数值,可能性是无限的。 如上例所示,我们甚至可以传入我们自己的对象(TestNGTest6_3_0)进行参数化测试

依赖性测试

“参数化测试”表示方法是依赖性测试,它将在所需方法之前执行。 如果依赖方法失败,则所有后续测试将会被跳过,不会被标记为失败。

JUnit 4

JUnit框架着重于测试隔离; 目前它不支持此功能。

TestNG

它使用“dependOnMethods”来实现依赖测试如下 -

@Test
public void method1() {
   System.out.println("This is method 1");
}

@Test(dependsOnMethods={"method1"})
public void method2() {
    System.out.println("This is method 2");
}

“method2()”只有在“method1()”运行成功的情况下才会执行,否则“method2()”将跳过测试。

结论

在考虑所有功能比较之后,建议使用TestNG作为Java项目的核心单元测试框架,因为TestNG在参数化测试,依赖测试和套件测试(分组概念)方面更加突出。 TestNG用于高级测试和复杂集成测试。 它的灵活性对于大型测试套件尤其有用。 此外,TestNG还涵盖了整个核心的JUnit4功能。这样说来,好像也没有理由使用JUnit了。

TestNG与spring或spring boot结合

mockito

mockito的官网:http://site.mockito.org/
在实际项目中写单元测试的过程中我们会发现需要测试的类有很多依赖,这些依赖项又会有依赖,导致在单元测试代码里几乎无法完成构建,尤其是当依赖项尚未构建完成时会导致单元测试无法进行。为了解决这类问题我们引入了Mock的概念,简单的说就是模拟这些需要构建的类或者资源,提供给需要测试的对象使用。业内的Mock工具有很多,也已经很成熟了,这里我们将直接使用最流行的Mockito进行实战演练,完成mockito教程。

EasyMock 以及 Mockito 都因为可以极大地简化单元测试的书写过程而被许多人应用在自己的工作中,但是这两种 Mock 工具都不可以实现对静态函数、构造函数、私有函数、Final 函数以及系统函数的模拟,但是这些方法往往是我们在大型系统中需要的功能。

如何使用Mockito?

第一步:在项目的pom中添加依赖,我用的阿里库的mockito版本为2.9.0的版本,ali的maven库中找到mockito-core的依赖jar,导入项目pom
也可以直接去官网下载相应的jar包,更新到了2.17版本。

第二步:另外Mockito需要Junit配合使用,在Pom文件中同样引入:junit4的版本。

第三步:然后为了使代码更简洁,最好在测试类中导入静态资源,还有为了使用常用的junit关键字,也要引入junit的两个类Before和Test:

import static org.mockito.Mockito.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;

第四步:然后就可以编写测试代码进行使用了,这里用junit的测试步骤来测试即可,mockito主要的功能就是模拟。。。

坚持原创技术分享,您的支持将鼓励我继续创作!
+