在第三节中不知道大伙有没有这么一个问题:
问题:
成千上万个测试用例如何管理?
上节已经讲了如何通过Selenium来打开浏览器,但是有没有发现我们的所有脚本启动都得通过JAVA的main函数来启动,那么问题来了,如果我们一个方法就是一个测试用例,那么当我们有成千上百个测试用例需要被执行时,怎么办?难道都通过main函数把所有的方法都加进去?
答案:
我们需要一个可以组织管理我们测试用例的框架。可以是Junit也可以是TestNG,而我们后面的课程都会以TestNG为例,进行讲解。
TestNG 简介:
TestNG类似Junit或者NUnit,但是TestNG提供了更加强大,更加方便,更加灵活的并且是开源的测试框架。 它几乎可以用在我们所有的测试环节,单元测试,基础测试, end-to-end测试,功能测试等等。。。
官方网站:http://testng.org/doc/
TestNG 测试框架给我们提供了什么?
- 提供强大的注释,方便测试人员的使用。
- 支持数据驱动测试(DDT)
- 支持并行测试
- 可以灵活配置测试,强大的执行模式
- 可生成多种测试报告
- 等等
安装
TestNG其实是一个jar包,所以我们可以通过配置我们的Maven工程来下载对应jar包。 修改pom.xml文件,添加如下:
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.11</version>
<scope>test</scope>
</dependency>
常用注解
@Test
标记一个类或方法作为测试的一部分。
标注一个类,则这个类里面是所有方法都将成为测试方法。
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
@Test
public class TestNGDemo01 {
public void test1(){
System.out.print("这个是test1");
}
public void test2(){
System.out.print("这个是test2");
}
public void test3(){
System.out.print("这个是test3");
}
}
通过IDEA直接运行,看到控制台运行结果:
标注一个方法,则该方法则为测试方法
如下面例子,我们只标注test1()和test2()为测试方法,我们再次执行这个类:
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@Test
public void test1(){
System.out.println("这个是test1");
}
@Test
public void test2(){
System.out.println("这个是test2");
}
public void test3(){
System.out.println("这个是test3");
}
}
最后我们发现控制台只打印了test1()和test2(),test3()没被标注则不再是一个测试方法:
如何描述一个测试方法
有时我们需要描述一个测试方法是做什么用的,除了通过JAVA的注解描述外,@Test注解也提供了描述的方法:
@Test(description = "这个是test1注解")
public void test1(){
System.out.println("这个是test1");
}
结果不会对输出有任何影响,但却让人很容易知道这个测试方法是做什么的:
如何设置测试方法的超时时间
如果你担心一个测试方法因为某些原因卡着迟迟不执行结束或者你觉得某个流程如果多长时间内如果没法执行结束那就得去优化,那么我们可以强制设置一个测试方法最长的测试时间。
@Test(timeOut = 2000)
public void test2() throws InterruptedException {
System.out.println("这个是test2");
Thread.sleep(3000);
}
如上代码,我们设置一个测试方法的timeOut 为2000毫秒,但是我们的测试方法体却要等待3000毫秒,所以这个测试方法,最后一定执行会抛出错误:
如何控制测试方法的执行顺序
在不做额外设置的情况下,测试方法的执行顺序是根据方法名的ASCII先后来执行的,例如下面的例子,我们把test2()放于test1()之前,然后执行这个测试类:
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@Test
public void test2() throws InterruptedException {
System.out.println("这个是test2");
Thread.sleep(3000);
}
@Test
public void test1(){
System.out.println("这个是test1");
}
@Test
public void test3(){
System.out.println("这个是test3");
}
}
执行结果如下,我们发现依旧test1()在test2()之前执行:
那么如果我们就想test2()在test1()之前执行呢?如下我们只需要给@Test加上“priorty”参数并设置顺序便可:
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@Test(priority = 1)
public void test2() throws InterruptedException {
System.out.println("这个是test2");
Thread.sleep(3000);
}
@Test(priority = 2)
public void test1(){
System.out.println("这个是test1");
}
@Test(priority = 3)
public void test3(){
System.out.println("这个是test3");
}
}
运行结果:
测试方法相互依赖
写测试用例时,我们尽可能得不要去写相互依赖的测试用例,Case依赖的另一个Case,那么另一个Case只是你这个Case的前提条件,所以就算离开另一个Case,你这个Case也应该能独立运行,也就是说Case要保持原子性。
同样自动化代码组织起来的测试方法(测试用例)我们也应该做到原子性,但要是某些特殊场景非得做到Case间相互依赖咋办?看如下代码,通过给@Test添加“dependsOnMethods”参数解决:
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@Test
public void test2(){
System.out.println("这个是test2");
}
@Test(dependsOnMethods = "test2")
public void test1(){
System.out.println("这个是test1");
}
@Test
public void test3(){
System.out.println("这个是test3");
}
}
如上代码,我们单独运行test1(),如果不加入依赖,那么只会运行test1(),但是我已经加上依赖了,那么执行test1()之前,它一定会先执行test2(),而test3()则不会被运行到:
@Test 注解还可以更很多别的参数,我们后面会有用到再讲。
@BeforeClass
在调用当前类的第一个测试方法之前运行,注释方法仅运行一次。
@AfterClass
在调用当前类的第一个测试方法之后运行,注释方法仅运行一次
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@BeforeClass
public void beforeClass() {
System.out.println("这个是 BeforeClass");
}
@AfterClass
public void afterClass() {
System.out.println("这个是 AfterClass");
}
@Test
public void test1() {
System.out.println("这个是 test1");
}
@Test
public void test2() {
System.out.println("这个是 test2");
}
}
我们整个类运行起来,查看运行结果如下,被@BeForeClass和@AfterClass标注的类我们只允许了一次,而且BeforeClass在所有的Test之前运行,AfterClass在所有的Test之后运行:
@BeforeTest
注释的方法将在属于<test>标签内的类的所有测试方法运行之前运行。
@AfterTest
注释的方法将在属于<test>标签内的类的所有测试方法运行之后运行。
import org.testng.annotations.*;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@BeforeClass
public void beforeClass() {
System.out.println("这个是 BeforeClass");
}
@AfterClass
public void afterClass() {
System.out.println("这个是 AfterClass");
}
@BeforeTest
public void beforeTest() {
System.out.println("这个是一个 BeforeTest");
}
@AfterTest
public void afterTest() {
System.out.println("这个是一个 AfterTest");
}
@Test
public void test1() {
System.out.println("这个是 test1");
}
@Test
public void test2() {
System.out.println("这个是 test2");
}
}
执行结果,如下图,我们看到BeforeTest和AfterTest也都只执行了一次,而且BeforeTest比BeforeClass还早执行,同时AfterTest晚于AfterClass执行:
@BeforeMethod
注释方法将在每个测试方法之前运行。
@AfterMethod
注释方法将在每个测试方法之后运行。
import org.testng.annotations.*;
/**
* Created by 米阳 on 2017/9/12.
*/
public class TestNGDemo01 {
@BeforeClass
public void beforeClass() {
System.out.println("这个是 BeforeClass");
}
@AfterClass
public void afterClass() {
System.out.println("这个是 AfterClass");
}
@BeforeTest
public void beforeTest() {
System.out.println("这个是一个 BeforeTest");
}
@AfterTest
public void afterTest() {
System.out.println("这个是一个 AfterTest");
}
@BeforeMethod
public void beforeMethod(){
System.out.println("这是一个 BeforeMethod");
}
@AfterMethod
public void afterMethod(){
System.out.println("这是一个 AfterMethod");
}
@Test
public void test1() {
System.out.println("这个是 test1");
}
@Test
public void test2() {
System.out.println("这个是 test2");
}
}
运行类结果如下,我们看到BeforeMethod在每个Test运行执行都执行一次,AfterMethod则在每个Test运行之后运行。同时BeforeMethod比BeforeClass和BeforeTest都后执行,先结束:
还有很多的注解,以后用到我们再讲。