Testng使用方法示例

TestNG

TestNG是一个测试框架,灵感来自JUnit和NUnit。但引入了下面这些新的功能,使它更强大和更容易使用。

  • 注解;
  • 可在任意大的线程池运行您的测试(所有方法在它们自己的线程内,一个线程一个测试类);
  • 灵活的测试配置;
  • 支持数据驱动测试(@DataProvider);
  • 支持参数;
  • 强大的执行模型(不再使用TestSuite);
  • 支持各种工具和插件(Eclipse,IDEA,Maven等…);
  • 嵌入BeanShell增加进一步的灵活性;
  • 默认使用JDK函数运行和日志记录(无依赖关系);

 

Eclipse配置TestNG

  1. 打开Eclipse —> Help —> Install New Software
  2. 然后点击Add,Name输入:TestNG,Location输入:http://beust.com/eclipse , 点击OK。
  3. 勾选TestNG,一路NEXT,按提示操作。

还有一种离线安装方式,适用于网络不佳的同学,这里不给出步骤了。使用搜索引擎吧同学们。

TestNG应用到项目

安装完成后,右键你的项目Build Path —> Add Libraries,选择TestNG,点击Finish.(如果这一步没有看到TestNG,请返回上一步检查你的安装是否成功)

下面是TestNG的最简单的一个例子

import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;
 
public class TestNGDemo {
    @BeforeClass
    public void setUp() {
        System.out.println("this is before class");
    }
 
    @Test
    public void testMethod() {
        System.out.println("this is TestNG test case");
    }
 
    @AfterClass
    public void tearDown() {
        System.out.println("this is after class");
    }
}

如何使用TestNG执行测试呢?在你的类文件内代码区域或者右键类文件,Run As —> TestNG Test

TestNG注解

注解

描述

@BeforeSuite

注解的方法将只运行一次,针对测试套件,在当前的测试套件运行前执行的方法。

@AfterSuite

注解的方法将只运行一次, 针对测试套件,在当前的测试套件运行后执行的方法。

@BeforeClass

注解的方法将只运行一次,在当前已经被调用的类的第一个测试方法运行前运行。

@AfterClass

注解的方法将只运行一次,在当前类的所有测试方法运行完成后运行。

@BeforeTest

针对测试套件, 在任何属于这个类的并且用@test标签标记的测试方法运行前运行

@AfterTest

针对测试套件,在任何属于这个类的并且用@test标签标记的测试方法运行后运行

@BeforeGroups

在属于这个组的第一个测试方法运行前运行

@AfterGroups

在属于这个组的最后一个测试方法被调用后运行

@BeforeMethod

在每个测试方法前运行

@AfterMethod

在每个测试方法后运行

@DataProvider

标志着提供数据的一个测试方法,注解的方法必须返回一个Object[][]

@Factory

标志着一个工厂方法,标记的方法将被用于返回TestNG的测试类的对象。该方法必须返回Object[]。

@Listeners

定义一个测试类的监听器。

@Parameters

将参数传递给@Test方法。

@Test

标记一个测试类或测试方法

暂时不理解上面的注解没关系,在接下来的例子中将一一阐述。


执行顺序

一个小例子,让我们看下注解的执行顺序

import org.testng.annotations.Test;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.AfterTest;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.AfterSuite;
 
public class TestngAnnotation {
 
    // test case 1
    @Test
    public void testCase1() {
        System.out.println("in test case 1");
    }
 
    // test case 2
    @Test
    public void testCase2() {
        System.out.println("in test case 2");
    }
 
    @BeforeMethod
    public void beforeMethod() {
        System.out.println("in beforeMethod");
    }
 
    @AfterMethod
    public void afterMethod() {
        System.out.println("in afterMethod");
    }
 
    @BeforeClass
    public void beforeClass() {
        System.out.println("in beforeClass");
    }
 
    @AfterClass
    public void afterClass() {
        System.out.println("in afterClass");
    }
 
    @BeforeTest
    public void beforeTest() {
        System.out.println("in beforeTest");
    }
 
    @AfterTest
    public void afterTest() {
        System.out.println("in afterTest");
    }
 
    @BeforeSuite
    public void beforeSuite() {
        System.out.println("in beforeSuite");
    }
 
    @AfterSuite
    public void afterSuite() {
        System.out.println("in afterSuite");
    }
}

执行后输出

in beforeSuite
in beforeTest
in beforeClass
in beforeMethod
in test case 1
in afterMethod
in beforeMethod
in test case 2
in afterMethod
in afterClass
in afterTest
PASSED: testCase1
PASSED: testCase2
 
===============================================
    Default test
    Tests run: 2, Failures: 0, Skips: 0
===============================================

因为执行方式的问题,afterSuite没有执行,这个先不用理会。

可以看到Suite是最先执行的,接下来执行Test和Class,三种注解都只执行了一次。

因为@Test方法有两个,而Method要在每个@Test方法执行时运行,所以也执行了两次。

是不是有点小晕了,大家这样理解,@Test是整个测试的核心和主体,所有Before都是前置依赖,after则都是队尾处最后执行。

用XML管理测试

我们先来看下TestNG.xml最简单的一个配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite"> 
    <test name="Test" > 
        <groups>
        </groups>
        <classes>
            <class name="com.sun.example.TestngAnnotation">
                <methods>
                </methods>
            </class>
        </classes>
    </test>
</suite>

该文件可以放在项目src/目录下。右键执行上面的文件,跟执行类文件同样效果,且afterSuite也会被执行。

结构分别是suite、test、class、groups和method层次,看到这里应该明白注解里的BeforeSuite、BeforeTest、BeforeClass、BeforeGroups、BeforeMethod等对应的是什么了吧。

suite name和test name都是自定义名字,但class name需要填写实际的测试类,记得要加包名。

文件节点属性说明

suite属性说明:
@name: suite的名称,必须参数    
@junit:是否以Junit模式运行,可选值(true | false),默认"false"
@verbose:命令行信息打印等级,不会影响测试报告输出内容;可选值(1|2|3|4|5) 
@parallel:是否多线程并发运行测试;可选值(false | methods | tests | classes | instances),默认 "false"
@thread-count:当为并发执行时的线程池数量,默认为"5"
@configfailurepolicy:一旦Before/After Class/Methods这些方法失败后,是继续执行测试还是跳过测试;可选值 (skip | continue),默认"skip"
@annotations:获取注解的位置,如果为"javadoc", 则使用javadoc注解,否则使用jdk注解
@time-out:为具体执行单元设定一个超时时间,具体参照parallel的执行单元设置;单位为毫秒
@skipfailedinvocationcounts:是否跳过失败的调用,可选值(true | false),默认"false"
@data-provider-thread-count:并发执行时data-provider的线程池数量,默认为"10"
@object-factory:一个实现IObjectFactory接口的类,用来实例测试对象
@allow-return-values:是否允许返回函数值,可选值(true | false),默认"false"
@preserve-order:顺序执行开关,可选值(true | false) "true"
@group-by-instances:是否按实例分组,可选值(true | false) "false"
 
test属性说明:
@name:test的名字,必选参数;测试报告中会有体现
@junit:是否以Junit模式运行,可选值(true | false),默认"false"
@verbose:命令行信息打印等级,不会影响测试报告输出内容;可选值(1|2|3|4|5) 
@parallel:是否多线程并发运行测试;可选值(false | methods | tests | classes | instances),默认 "false"
@thread-count:当为并发执行时的线程池数量,默认为"5"
@annotations:获取注解的位置,如果为"javadoc", 则使用javadoc注解,否则使用jdk5注解
@time-out:为具体执行单元设定一个超时时间,具体参照parallel的执行单元设置;单位为毫秒
@enabled:设置当前test是否生效,可选值(true | false),默认"true" 
@skipfailedinvocationcounts:是否跳过失败的调用,可选值(true | false),默认"false"
@preserve-order:顺序执行开关,可选值(true | false) "true"
@group-by-instances:是否按实例分组,可选值(true | false) "false"
@allow-return-values:是否允许返回函数值,可选值(true | false),默认"false"

更多testng配置及说明,请移步http://testdoc.org/docmaster?pid=111

分组

看下面的小例子

import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;
import org.testng.annotations.Test;
 
public class TestngGroups {
 
    @BeforeGroups(groups = { "group1"})
    public void beforeGroups() {
        System.err.println("in before group1");  
    }
 
    @AfterGroups(groups = { "group1"})
    public void afterGroups() {
        System.err.println("in after group1");  
    }
 
    @Test(groups = { "group1", "group2" })  
    public void testMethod1() {  
        System.err.println("groups = { group1, group2 }");  
    }  
 
    @Test(groups = { "group1" })  
    public void testMethod2() {  
        System.err.println("groups = { group1 }");  
    }  
 
    @Test(groups = { "group2" })  
    public void testMethod3() {  
        System.err.println("groups = { group2 }");  
    }  
 
}

用xml来管理测试

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite"> 
    <test name="Test" > 
        <groups>
            <run>
                <include name="group1"></include>
            </run>
        </groups>
        <classes>
            <class name="com.sun.example.TestngGroups">
            </class>
        </classes>
    </test>
</suite>

执行后输出

in before group1
groups = { group1, group2 }
groups = { group1 }
in after group1
 
===============================================
Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

可以看到我们共有三个@Test,一个属于group1一个属于group2 ,还有一个同属于group1, group2。

然后我们在xml文件中groups节点下,只run了分组group1,所以并没有执行属于group2的那个@Test

参数化

在大多数情况下,你会遇到这样一个场景,业务逻辑需要一个巨大的不同数量的测试。
参数测试,允许测试人员一遍又一遍使用不同的值,运行同样的测试。

TestNG有两种不同的方式让你直接传递参数:

使用testng.xml
数据提供程序

使用testng.xml

在testng.xml文件中定义参数,然后在源文件中引用这些参数。让我们看看下面的例子中如何使用这种技术来传递参数。

创建一个类文件,如下:

public class ParameterizedTest1 {
    @Test
    @Parameters("myName")
    public void parameterTest(String myName) {
        System.out.println("Parameterized value is : " + myName);
    }
}

创建 testng.xml,如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite">
    <test name="test">
        <parameter name="myName" value="sun"/> 
        <classes>
            <class name="ParameterizedTest1" />
        </classes>
    </test>
</suite>

执行后输出

Parameterized value is : sun
 
===============================================
Suite
Total tests run: 1, Failures: 0, Skips: 0
===============================================

先看下testng.xml,可以看到test节点下有一个parameter子节点,这个就是定义参数的位置。
name自定义,但你在代码处引用时需要记住你写的name,value填写你要传的值。
当然我们也可以把parameter节点放在suite下,意味着该参数在整个suite下的所有test都是共享的。

TestNG 对testng.xml 的参数的类型指定的值会自动尝试转换。下面是支持的类型:

* String
* int/Integer
* boolean/Boolean
* byte/Byte
* char/Character
* double/Double
* float/Float
* long/Long
* short/Short

数据提供程序

当你需要更复杂的参数,在这种情况下,你可以使用数据提供程序。用@DataProvider批注,这个注解只有一个字符串属性:它的名字。如果不提供名称,数据提供程序的名称会默认为方法的名称。数据提供程序返回一个对象数组。

让我们来看下面的例子:

public class ParamTestWithDataProvider1 {
 
    @DataProvider(name = "params")
    public static Object[][] primeNumbers() {
        return new Object[][] {{1, 2 }, {2, 2}, {3, 4}, {4, 4}, {5, 6}};
    }
 
    @Test(dataProvider = "params")
    public void testPrimeNumberChecker(Integer inputNumber1, Integer inputNumber2) {
        if (inputNumber1 == inputNumber2) {
            System.out.println("相等的 [" + inputNumber1 + " " + inputNumber2 + "]");
        } else {
            System.out.println("不相等的 [" + inputNumber1 + " " + inputNumber2 + "]");
        }
    }
}

创建 testng.xml,如下:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite">
    <test name="test">
        <classes>
            <class name="ParamTestWithDataProvider1" />
        </classes>
    </test>
</suite>

执行后输出

不相等的 [1 2]
相等的 [2 2]
不相等的 [3 4]
相等的 [4 4]
不相等的 [5 6]
PASSED: testPrimeNumberChecker(1, 2)
PASSED: testPrimeNumberChecker(2, 2)
PASSED: testPrimeNumberChecker(3, 4)
PASSED: testPrimeNumberChecker(4, 4)
PASSED: testPrimeNumberChecker(5, 6)
 
===============================================
    Default test
    Tests run: 5, Failures: 0, Skips: 0
===============================================

DataProvider共提供了五组数据,供测试方法testPrimeNumberChecker来调用。
来看输出结果,每组数据依次调用了测试方法,共执行了五次。
上面的示例就是最简单的数据驱动测试,用定义的数据来控制测试行为和业务逻辑。

异常测试

测试中,有时候我们期望某些代码抛出异常。TestNG 为异常处理代码提供了一个选项,可以选择是否需要代码抛出异常或者不抛出。TestNG通过@Test(expectedExceptions) 来判断期待的异常,并且判断异常Message

来看下面的例子:

import org.testng.annotations.Test;
 
public class ExceptionDemo {
 
    @Test(expectedExceptions = ArrayIndexOutOfBoundsException.class, 
            expectedExceptionsMessageRegExp = "IndexOutOfBounds")
    public void testException(){
        throw new ArrayIndexOutOfBoundsException("IndexOutOfBounds");
    }
}

执行后输出

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

我们抛出了ArrayIndexOutOfBoundsException异常,并且在expectedExceptions的value里声明了期待的异常 ArrayIndexOutOfBoundsException.class.
抛出的异常等于期待的异常,并且ExceptionMessage也相符。达到了我们的测试目的。

我们稍微改动一下上面的例子

import org.testng.annotations.Test;
 
public class ExceptionDemo {
 
    @Test(expectedExceptions = ArrayIndexOutOfBoundsException.class, 
            expectedExceptionsMessageRegExp = "IndexOutOfBounds")
    public void testException(){
        throw new ArrayIndexOutOfBoundsException("IndexOutOf");
    }
}

执行后输出

FAILED: testException
org.testng.TestException: 
Expected exception java.lang.ArrayIndexOutOfBoundsException but got org.testng.TestException: 
The exception was thrown with the wrong message: expected "IndexOutOfBounds" but got "IndexOutOf"
    at org.testng.internal.Invoker.handleInvocationResults(Invoker.java:1497)
    at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:1245)
    at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:127)
    at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:111)
    at org.testng.TestRunner.privateRun(TestRunner.java:767)
    at org.testng.TestRunner.run(TestRunner.java:617)
    at org.testng.SuiteRunner.runTest(SuiteRunner.java:334)
    at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:329)
    at org.testng.SuiteRunner.privateRun(SuiteRunner.java:291)
    at org.testng.SuiteRunner.run(SuiteRunner.java:240)
    at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
    at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:86)
    at org.testng.TestNG.runSuitesSequentially(TestNG.java:1224)
    at org.testng.TestNG.runSuitesLocally(TestNG.java:1149)
    at org.testng.TestNG.run(TestNG.java:1057)
    at org.testng.remote.RemoteTestNG.run(RemoteTestNG.java:111)
    at org.testng.remote.RemoteTestNG.initAndRun(RemoteTestNG.java:204)
    at org.testng.remote.RemoteTestNG.main(RemoteTestNG.java:175)
 
    ...... 此处省略若干报错信息
===============================================
    Default test
    Tests run: 1, Failures: 1, Skips: 0
===============================================

可以看到我们抛出的异常和期待的异常是相符的。
而ExceptionsMessage我们抛出了"IndexOutOf",期待的却是 "IndexOutOfBounds",所以测试失败。

没有应用到实际的自动化测试中,大家可能会感觉到迷惑。在前面的selenium webdriver练习中,你们应该会经常遇到一个异常:NoSuchElementException(没有找到元素). 现在大家设想这么一个场景,我们要测试某个页面的一个按钮不应该显示,如果显示则测试失败。那么测试就可以像下面这样写:

public class ExceptionDemo {
 
    @Test(expectedExceptions = NoSuchElementException.class)
    public void buttonIsNotDisplayed() {
        WebElement button = driver.findElement(By.id("button"));
        button.click();
    }
}

 

 

Assert/Log/Report

Assert用来校验测试的结果。
Log: 类似于Log4j的log记录。
Report: 输出本次测试的结果报告。

下面只讲下简单的使用:

Assert

常用方法介绍:

fail 直接失败测试用例,可以抛出异常。
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 判断忽略顺序是否相等

例子

public class AssertDemo {
 
    public void assertName(String name) {
        Assert.assertEquals(name, "sun", "姓名不相符,请检查。");
    }
 
    @Test
    public void checkName() {
        assertName("haha");
    }
}

示例是assertEquals(String actual, String expected, String message)方法,判断两个值是否相等。
来看方法的参数,第一个是实际值,第二个是预期值,第三个message意思是如果不相等则需要提示的信息。 我们预期的值是“sun”,但传入了“haha”,所以测试是失败的。

输出结果

FAILED: checkName
java.lang.AssertionError: 姓名不相符,请检查。 expected [sun] but found [haha]
    at org.testng.Assert.fail(Assert.java:94)
    at org.testng.Assert.failNotEquals(Assert.java:494)
    at org.testng.Assert.assertEquals(Assert.java:123)
    at org.testng.Assert.assertEquals(Assert.java:176)
    at com.sun.example.AssertDemo.assertName(AssertDemo.java:9)
    at com.sun.example.AssertDemo.checkName(AssertDemo.java:14)
    ......省略若干
 
===============================================
    Default test
    Tests run: 1, Failures: 1, Skips: 0
===============================================

合理的使用Assert会上你的测试更健壮,直观,易维护,定位错误更快速。
其它的Assert方法大同小异,不再多做介绍。

Log

跟Java最知名的Log4j很类似

首先在工程src/下新建一个log4testng.properties文件,内容为:

log4testng.debug=true
 
log4testng.rootLogger=DEBUG
 
log4testng.logger.org.testng.reporters.EmailableReporter=TRACE
 
log4testng.logger.org.testng=WARN

用了最简单的log规则,还可以添加很多定制内容,不多做介绍。

下面在代码中应用

public class LoggerDemo {
    public static Logger logger = Logger.getLogger(LoggerDemo.class);  
 
    @Test
    public void loggerDemo() {  
        logger.debug("这是调试信息");  
        logger.info("测试是通过的");
        logger.warn("这是一个警告");
        logger.error("出现一个错误");  
    }  
}

执行后输出

[LoggerDemo] [DEBUG] 这是调试信息
[LoggerDemo] [INFO] 测试是通过的
[LoggerDemo] [WARN] 这是一个警告
[LoggerDemo] [ERROR] 出现一个错误
PASSED: loggerDemo
 
===============================================
    Default test
    Tests run: 1, Failures: 0, Skips: 0
===============================================

如果想要输出结果更加详细,可以在log4testng.properties文件内定制规则。 还可以让日志显示时间,测试方法,代码行等等,如下面用log4j输出的一条log:

[INFO ] 2016-06-17 10:29:55 method:com.allinmd.util.AppiumServer.iOSDriverRun(AppiumServer.java:164)
swipe欢迎页

跟Assert相同,合理的使用Log,可以让你的错误定位更明确。

Report

TestNG自带的报告模板略丑,不忍直视。所以采用了另外一个开源的项目ReportNG, 它是TestNG的一个HTML报表生成插件,用于替换TestNG默认的HTML报表。ReportNG提供一种简单的方式来查看测试结果,并能够对结 果代码进行着色。还可以通过修改CSS文件来替换默认的输出样式,修改源码改变模板。

第一步下载reportng-1.1.4jar包 下载velocity-1.4.jar
第二步导入到项目,这个就不用重复了吧,忘了的自己面壁思过。
第三步在TestNG.xml文件配置listener监听:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite"> 
    <listeners>
        <listener class-name="org.uncommons.reportng.HTMLReporter"/>
        <listener class-name="org.uncommons.reportng.JUnitXMLReporter"/>
    </listeners>
    <test name="Test" > 
        <classes>
            <class name="com.sun.example.AssertDemo">
            </class>
        </classes>
    </test>
</suite>

输出报告示例

UI自动化测试用例实践

下面是唯医用户登录的例子,运用了TestNG里面的一些方法。

public class AllinLoginDemo {
    private WebDriver driver;
    public static Logger logger = Logger.getLogger(AllinLoginDemo.class);  
 
    /**
     * 启动一个ChromeDriver实例,并链接到唯医首页
     */
    @BeforeClass
    public void setUp() {
        driver = new ChromeDriver();
        driver.manage().window().maximize();
        driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
        driver.get("http://www.allinmd.cn");
    }
 
    /**
     * 唯医登录
     */
    @Test (priority = 1)
    public void allinLogin() {
        logger.info("开始唯医用户登录");
        WebElement username = driver.findElement(By.xpath(".//*[@id='allinLogin']/div[1]/div[3]/input"));
        username.sendKeys("17700020000");
 
        WebElement password = driver.findElement(By.xpath(".//input[@placeholder='你的密码']"));
        password.sendKeys("testuser111111");
 
        WebElement login_button = driver.findElement(By.xpath("//*[@id='allinLogin']/div/div[7]/div"));
        login_button.click();
    }
 
    /**
     * 检查登录后跳转
     */
    @Test (priority = 2)
    public void checkLogin() {
        waitDownPage("我的首页-唯医,allinmd", 15);
        Assert.assertEquals(driver.getTitle(), "我的首页-唯医,allinmd", "没有跳转到首页,请检查是否登录成功。");
        logger.info("唯医用户登录成功");
    }
 
    /**
     * 关闭浏览器,并退出driver实例
     */
    @AfterClass
    public void tearDown() {
        driver.quit();
    }
 
    /**
     * 等待页面跳转
     * 直到当前title不等于传入的title或者超时
     * @param waitPageTitle
     */
    public void waitDownPage(String currenTitle, int timeout) {
        int num = 0;
        while(!driver.getTitle().contains(currenTitle) && num < timeout) {
            sleep(1);
            num ++;
        }
    }
 
    /**
     * Thread.sleep
     * @param d
     */
    public void sleep(double d) {
        try {
            d *= 1000;
            Thread.sleep((int)d);
        } catch(Exception e) {}
    }
}

上面是一个唯医登录的自动化测试用例,现在假设还有个唯医注册的自动化测试用例。
我们testng.xml就可以像下面这样写:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite"> 
    <test name="case01-唯医用户登录" > 
        <classes>
            <class name="com.sun.example.AllinLoginDemo">
            </class>
        </classes>
    </test>
    <test name="case02-唯医用户注册" > 
        <classes>
            <class name="com.sun.example.AllinRegisterDemo">
            </class>
        </classes>
    </test>
</suite>

执行后输出

[AllinLoginDemo] [INFO] 开始唯医用户登录
[AllinLoginDemo] [INFO] 唯医用户登录成功
 
===============================================
Suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================

 

posted @ 2016-12-12 16:54  "花田李氏  阅读(578)  评论(0编辑  收藏  举报