注解
- @BeforeSuite 在此套件所有的测试方式之前运行
- @AfterSuite 在此套件所有的测试方式之后运行
- @BeforeTest 在<test> 标记内的类所有的测试方法之前运行
- @AfterTest 在<test>标记内的类所有的测试方式之后运行
- @BeforeGroups 在当前组所有测试方式运行之前运行
- @AfterGroups 在当前组所有测试方式之后运行
- @BeforeClass 在当时类所有测试方法之前运行
- @AfterClass 在当前类所有测试方法之后运行
- @BeforeMethod 在每一个测试方式运行之前运行
- @AfterMehod 在每一个测试方法之后运行
子类会继承父类的@Before*和@After*方法,代码如下, 不会继承@Test方法
package org.xsn.autotest.testcase; import org.testng.annotations.AfterClass; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeClass; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class Test1 { @BeforeClass public void setUp() throws Exception { System.out.println("BeforeClass in invoke super class"); } @BeforeMethod void setUpMethod(){ System.out.println("in run suprt class BeforeMethod"); } @AfterMethod void afterMethod() { System.out.println("AfterMethod in super class"); } @AfterClass void afterClass() { System.out.println("Afterclass in super class"); } } class SubTest extends Test1{ @BeforeClass public void setUp1() throws Exception { System.out.println("BeforeClass in invoke sub class"); } @Test void tes1(){ System.out.println("test1 method run in subclass"); } }
可以看出,执行的顺序和在一个类中没什么区别, 子类和父类有相同的Before时, 会先初始化父类, 不能方法名相同, 会造成重写
属性
- alwaysRun 总是运行, 即使不属于同一个组
- dependsOnGroups 所依赖的组
- dependsOnMethods 所依赖的方法
- enabled 可用于Before*和After* 以及Test注解, 作用一直, enabled = true为默认, 忽略为enabled = false
- groups 所属组, 可用于Before*和After* 以及Test注解,
- inheritGroups 默认是true, 意思是指定为与类所属的组属于同一个组, false为不是同一个组, 可用@Before*和@After* eg.
1 package org.xsn.autotest.testcase; 2 3 import org.testng.annotations.BeforeClass; 4 import org.testng.annotations.BeforeMethod; 5 import org.testng.annotations.Test; 6 7 @Test(groups = {"group1"}) 8 public class Test23 { 9 @BeforeClass(inheritGroups = false) 10 public void setUp() { 11 System.out.println("setUp!"); 12 } 13 14 @BeforeMethod(inheritGroups = true) 15 public void test2() { 16 17 } 18 @Test(groups = "group2") 19 public void test1() { 20 System.out.println("test1 method running!"); 21 } 22 23 }
当inheritGroups = false,不会运行, 因为不属于group1,当inheritGroups = true时, 会运行, 默认也是inheritGroups = true, 这时这个方法属于group1,以上方法用配置文件运行group1组进行测试
- onlyForGroups 不知道什么玩意, 官网上的也没有看懂
@Parameteres
package org.xsn.autotest.testcase; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Optional; import org.testng.annotations.Parameters; import org.testng.annotations.Test; public class TestParameters { @Parameters("brower") @BeforeMethod public void setUp(@Optional("encode") String brower){ System.out.println(brower); } @Parameters({"name","age"}) @Test
public void testSingleString(String name, String age) { System.out.println(name); System.out.println(age); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="parametersuite"> <test name="parametertest"> <parameter name="brower" value="chrome"></parameter> <parameter name="name" value="lwf"></parameter> <parameter name="age" value="15"></parameter> <classes> <class name="org.xsn.autotest.testcase.TestParameters"></class> </classes> </test> </suite>
DataProviders的参数
package org.xsn.autotest.testcase; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestData { @DataProvider(name = "db") public static Object[][] db2() { return new Object[][] { { "lwf", new Integer(34) }, { "lwt", new Integer(23) } }; } @Test(dataProvider = "db2", dataProviderClass = TestDb.class) public void test1(String name, Integer age) { System.out.println(name); System.out.println(age); } } class TestDb{ @DataProvider(name="db2") public static Object[][] db2() { return new Object[][] { {"lwf", new Integer(34)}, {"lwt", new Integer(24)} }; } }
1 可以返回一个对象数组,
2 可以返回一个迭代对象,懒惰加载
3 must return either Object[][] or Object[] or Iterator<Object[]> or Iterator<Object>
打印调用参数的测试方法
package org.xsn.autotest.testcase; import java.lang.reflect.Method; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestInjection { @DataProvider public Object[][] createData(Method m){ System.out.println(m.getName()); return new Object[][] { new Object[] { "Cedric" }}; } @Test(dataProvider = "createData") public void test1(String s) { } @Test(dataProvider = "createData") public void test2(String s) { } }
@DataProvider(parallel = true)
parallel = flase
package org.xsn.autotest.testcase; import java.lang.reflect.Method; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestInjection { @DataProvider public Object[][] createData(Method m){ System.out.println(m.getName()); return new Object[][] { new Object[] { "Cedric" }, new Object[] { "Lwf" }, new Object[] { "lwt" } }; } @Test(dataProvider = "createData") public void test1(String s) { System.out.println(); System.out.println(Thread.currentThread()); System.out.println(Thread.activeCount()); } }
parallel = true
package org.xsn.autotest.testcase; import java.lang.reflect.Method; import org.testng.annotations.DataProvider; import org.testng.annotations.Test; public class TestInjection { @DataProvider(parallel = true) public Object[][] createData(Method m){ System.out.println(m.getName()); return new Object[][] { new Object[] { "Cedric" }, new Object[] { "Lwf" }, new Object[] { "lwt" } }; } @Test(dataProvider = "createData") public void test1(String s) { System.out.println(s); System.out.println(Thread.currentThread()); System.out.println(Thread.activeCount()); } }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="suite_parallel" data-provider-thread-count="10"> <test name="test_parallel"> <classes> <class name="org.xsn.autotest.testcase.TestInjection"></class> </classes> </test> </suite>
@Factory
1 return Object[] , 返回对象可以是任何类。
2 可以和@Test, @After*和@Before*一样接受参数
简单例子
package org.xsn.autotest.testcase; import org.testng.annotations.Factory; public class Test4 { @Factory public Object[] creatInstances() { Object[] result = new Object[10]; for (int i = 0; i < result.length; i++) { result[i] = new WebTest(i * 10); } return result; } }
package org.xsn.autotest.testcase; import org.testng.annotations.Test; public class WebTest { public static int count=0; private int m_numberOfTimes; public WebTest(int numberOfTimes) { m_numberOfTimes = numberOfTimes; System.out.println(m_numberOfTimes); } @Test public void testServer() { count++; System.out.println(count); } }
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="factory_suite">
<test name="factory_test">
<classes>
<class name="org.xsn.autotest.testcase.Test4"/>
</classes>
</test>
</suite>
通过打印构造方法可知, WebTest类被初始化了10次,TestNg测试方法也被调用了10次
@Factory(dataProvider = "db") 有一部分官网写的太迷糊, 我没有怎么看懂, 但是总感觉实用性不高, 以后有需要在补充吧。
类级别注释
@Test 可加到类上, 可加方法, 局部优先全局,类上只能声明类中public方法为TestNg方法
忽略测试
@Ignore和(enabled = false)在方法上使用相同, 在类上使用(enabled = false)按照优先级生效,@Ignore也可以忽略包
套件运行
org.testng.TestNG suitethreadpoolsize 3 testng1.xml testng2.xml testng3.xml, 指定三个测试套件在三个单独的线程中运行
方法运行
<suite name="factory_suite" parallel="methods" thread-count="5">
TestNg将在不同的线程中运行所有的测试方法, 依赖方法也将在单独的线程中运行
测试运行
<suite name="factory_suite" parallel="tests" thread-count="5">
TestNG将在同一个线程中运行相同<test>标记中的所有方法,但每个<test>标记将位于一个单独的线程中。这允许您在同一个<test>中对所有非线程安全的类进行分组,并保证它们将在同一个线程中运行,同时利用TestNG尽可能多的线程来运行测试。
类运行
<suite name="factory_suite" parallel="classes" thread-count="5">
TestNG将在同一个线程中运行同一个类中的所有方法,但每个类将在一个单独的线程中运行
<suite name="factory_suite" parallel="instances" thread-count="5">
TestNG将在同一个线程中的同一个实例中运行所有方法,但两个不同实例上的两个方法将在不同的线程中运行
总结一下, 以上就是以方法为单位的话, 就是一个线程运行一个方法, 以test为单位的话, 就是一个线程运行一个test, class, instances一个道理。
失败时重试测试
1 实现IRetryAnalyzer接口
2 绑定eg。@Test(retryAnalyzer = MyIRetry.class)
package org.xsn.autotest.testcase; import org.testng.Assert; import org.testng.IRetryAnalyzer; import org.testng.ITestResult; import org.testng.annotations.Test; public class MyIRetry implements IRetryAnalyzer { private int retryCount = 0; private static final int maxRetryCount = 2; @Override public boolean retry(ITestResult result) { if (retryCount < maxRetryCount) { retryCount++; return true; } return false; } } @Test(retryAnalyzer = MyIRetry.class) class TestclassSample{ static int count =0; public void test2() { count++; System.out.println(count); Assert.fail(); } }
监听器
org.testng.ITestListener
package org.xsn.autotest.testcase;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;
public class Test3 implements ITestListener{
@Override
public void onTestStart(ITestResult result) {
// TODO Auto-generated method stub
System.out.println("每个测试用例开始要做什么");
}
@Override
public void onTestSuccess(ITestResult result) {
// TODO Auto-generated method stub
System.out.println("每个测试用例运行成功要做什么"+result.getName());
}
@Override
public void onTestFailure(ITestResult result) {
// TODO Auto-generated method stub
System.out.println("每个测试用例运行失败要做什么");
}
@Override
public void onTestSkipped(ITestResult result) {
// TODO Auto-generated method stub
System.out.println("测试用例被跳过要做什么");
}
@Override
public void onTestFailedButWithinSuccessPercentage(ITestResult result) {
// TODO Auto-generated method stub
System.out.println("shishishui"+result.getName());
}
@Override
public void onStart(ITestContext context) {
// TODO Auto-generated method stub
System.out.println("测试开始要做什么");
}
@Override
public void onFinish(ITestContext context) {
// TODO Auto-generated method stub
System.out.println("测试结束要做什么");
}
}
package org.xsn.autotest.testcase;
import org.testng.Assert;
import org.testng.annotations.Test;
//@Listeners(Test3.class)
public class Test4{
@Test
public void test1() {
Assert.assertTrue(true, "haha");
System.out.println("test1 running");
}
@Test
public void test2() {
Assert.assertTrue(true, "xixi");
System.out.println("test2 running");
}
@Test(dependsOnMethods = "test2")
public void test3() {
System.out.println("test3 running");
}
@Test
public void test4() {
Assert.assertFalse(true);
System.out.println("test4 running");
}
@Test(dependsOnMethods = "test4")
public void test5() {
Assert.assertTrue(true, "dada");
System.out.println("test5 running");
}
}
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" > <suite name="login"> <test name="testlogin"> <classes> <class name="org.xsn.autotest.testcase.Test4"></class> </classes> </test> <listeners> <listener class-name="org.xsn.autotest.testcase.Test3"></listener> </listeners> </suite>
org.testng.IReporter
package org.xsn.autotest.testcase; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import org.testng.IReporter; import org.testng.IResultMap; import org.testng.ISuite; import org.testng.ISuiteResult; import org.testng.ITestContext; import org.testng.ITestNGMethod; import org.testng.xml.XmlSuite; public class XSNReport implements IReporter { @Override public void generateReport(List<XmlSuite> xmlSuites, List<ISuite> suites, String outputDirectory) { // TODO Auto-generated method stub // suites包含所有测试的结果集 for (ISuite iSuite : suites) { // 获取单个套件的结果 Map<String, ISuiteResult> results = iSuite.getResults(); // 获取map的键 Set<String> keySet = results.keySet(); for (String key : keySet) { // 编辑set集合, 根据key取value, 在从value中使用getTestContext()方法拿到ITestContext ITestContext context = results.get(key).getTestContext(); // 打印套件的详细信息到控制台 System.out.println("Suite Name-->" + context.getName() + "::Report output Ditectory-->" + context.getOutputDirectory() + "::Suite Name->" + context.getSuite().getName() + "::Start Date Time for execution->" + context.getStartDate() + "::End Date Time for execution->" + context.getEndDate()); // 获取失败的方法的IResultMap IResultMap tests = context.getFailedTests(); Collection<ITestNGMethod> methods = tests.getAllMethods(); System.out.println("--------FAILED TEST CASE---------"); for (ITestNGMethod failMethod : methods) { //打印失败的测试用例的详细 System.out.println("TESTCASE NAME->"+failMethod.getMethodName() +" Description->"+failMethod.getDescription() +" Priority->"+failMethod.getPriority() +" :Date->"+new Date(failMethod.getDate())); } } } } }
原文见:https://www.guru99.com/pdf-emails-and-screenshot-of-test-reports-in-selenium.html
原文见: https://testng.org/doc/documentation-main.html#native-dependency-injection