TestNG - 如何 运行 在每个测试结束时使用相同的方法
TestNG - how to run the same method at the end of each test
我有类似的东西:
@Test(priority = 1)
public void test1() {
testSomething1();
Assert.assertFalse(errorsExists());
}
@Test(priority = 2)
public void test2() {
testSomething2();
Assert.assertFalse(errorsExists());
}
@Test(priority = 3)
public void test3() {
testSomething3();
Assert.assertFalse(errorsExists());
}
并且我想将 Assert.assertFalse(errorsExists())
移动到 BaseTestCase
或 TestListener
这样我就不必每次都在测试结束时通过它。
我试图将它移动到 TestsListener 到 onFinish
,但是方法 errorsExists()
需要驱动程序,我无法将其放入其中。
更新:
我想方法 errorsExists() 影响测试结果。假设在 test2 方法中 errorsExists return true -> 我想要得到以下结果:
测试1通过
测试 2 失败
测试 3 通过
据我所知,我不能将此方法用于任何 @After 注释,也不能将其用于 TestListener 中的 onTestFailure 或 onTestSuccess
您应该能够将其移至使用@AfterMethod 注释的新方法。任何用@AfterMethod 注解的方法都会在每个测试方法执行后执行。这样的事情应该有效:
@Test(priority = 1)
public void test1() {
testSomething1();
//Assert.assertFalse(errorsExists());
}
@Test(priority = 2)
public void test2() {
testSomething2;
//Assert.assertFalse(errorsExists());
}
@Test(priority = 3)
public void test3() {
testSomething3();
//Assert.assertFalse(errorsExists());
}
@AfterMethod
public void assertError() {
Assert.assertFalse(errorsExists());
}
如果您 运行 每个 @Test 方法是并行的,那么您可以通过以下方式实现。但前提是,每个
@Test 应该有自己的 WebDriver 实例。您可以使用 ThreadLocal 变量来实现这一点。例如:
public class Driver {
public static ThreadLocal<AppiumDriver> driver = new ThreadLocal<>();
public static AppiumDriver getDriver() {
return driver.get();
}
public synchronized void initalizeDriver(String deviceName, String platformVersion, String port, String udid) {
if (deviceName.contains("iPhone")) {
setIOSCapabilities(driver, deviceName, platformVersion, port, udid);
} else if (deviceName.equalsIgnoreCase("pcloudy-apple")) {
setPcloudyIOSCapabilties(driver,platformVersion);
} else {
if (deviceName.contains("R-")) {
setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
} else if (deviceName.equalsIgnoreCase("pcloudy-Android")) {
setPcloudyAndroidCapabilties(driver,platformVersion);
} else {
startAndroidEmulator(deviceName, udid);
setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
}
}
}
}
public void setAndroidCapabilities(ThreadLocal<AppiumDriver> driver, String device, String platformVersion, String port, String udid) {
try {
File sourceDir = new File("src");
File app = new File(sourceDir, ANDROID_APP_PATH);
DesiredCapabilities desiredCapabilties = new DesiredCapabilities();
desiredCapabilties.setCapability(MobileCapabilityType.DEVICE_NAME, device);
desiredCapabilties.setCapability(AndroidMobileCapabilityType.IGNORE_UNIMPORTANT_VIEWS,true);
driver.set(new AndroidDriver<>(new URL(APPIUM_DEFAULT_URL), desiredCapabilties));
} catch (Exception e) {
log.error(e.getMessage());
log.error("Exception in launching the Android Driver " + e);
e.printStackTrace();
}
}
基础中的方法class为每个@Test 方法启动一个新的驱动程序实例
@BeforeMethod(alwaysRun = true)
@Parameters(value={"deviceName","platformVersion","port","udid"})
public synchronized void executeBeforeTest(String deviceName, String platformVersion,
@Optional("Port Required") String port, @Optional("UDID Required") String udid){
Driver driverObj = new Driver();
Thread.currentThread().setName(deviceName);
driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
if(Driver.getDriver() == null) {
driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
}
}
终于找到你要找的TestListener了class,
public class TestListener extends UITest implements ITestListener {
@Override
public void onTestFailure(ITestResult iTestResult) {
log.info("Driver getDriver() value is :: "+Driver.getDriver().toString());
log.info("Driver getSessionId() value is :: "+Driver.getDriver().getSessionId().toString());
if (Driver.getDriver() != null || Driver.getDriver().getSessionId() != null) {
try {
if (Driver.getDriver() instanceof IOSDriver) {
JavascriptExecutor js = (JavascriptExecutor) Driver.getDriver();
Map<String, Object> params = new HashMap<>();
params.put("bundleId", DeviceCapabalities.IOS_APP_BUNDLE_ID);
final Long state = (Long) js.executeScript("mobile: queryAppState", params);
System.out.println("Application state code is :" + state);
if (state == 1) {
log.error("Application has Crashed");
}
} else {
if (!(((AndroidDriver) (Driver.getDriver())).currentActivity().contains("app.name"))) {
log.error("Application has Crashed");
}
}
saveScreenshot(Driver.getDriver(),iTestResult);
} catch (Exception e) {
log.error("Exception :: " + e);
e.printStackTrace();
Assert.fail("Test case failed due to exception " + e);
}
}
}
您可以使用 IHookable
界面来实现。这通常(根据文档)用于在测试开始之前进行一些操作。但它也适用于每次测试结束时的操作。
创建一个实现此接口的 BaseTest
并让您的测试 类 扩展 BaseTest
。
public class BaseTest implements IHookable {
@Override
public void run(IHookCallBack cb, ITestResult testResult) {
cb.runTestMethod(testResult); // invokes the actual test case
Assert.assertFalse(errorsExists());
}
}
您可以调用一些代码并使用 IInvokedMethodListener
修改测试结果。
请注意,这是基于您的代码示例的非常简单的实现。
它可能需要一些改进。
测试Class:
@Listeners(ErrorsExistsListener.class)
class MyTest {
@Test(priority = 1)
public void test1() {
testSomething1();
}
@Test(priority = 2)
public void test2() {
testSomething2;
}
@Test(priority = 3)
public void test3() {
testSomething3();
}
boolean errorsExists() {
// some logic
}
}
测试监听器:
class ErrorsExistsListener implements IInvokedMethodListener {
@Override
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (method.isTestMethod() && result.getStatus() != ITestResult.FAILURE) {
Object[] instances = result.getTestClass().getInstances(false);
MyTest myTestClass = (MyTest) instances[0]; // you'll get exception here if set this listener for non-MyTest class.
try {
Assert.assertFalse(myTestClass.errorsExists());
} catch (AssertionError e) {
result.setStatus(ITestResult.FAILURE);
result.setThrowable(e);
}
}
}
}
我有类似的东西:
@Test(priority = 1)
public void test1() {
testSomething1();
Assert.assertFalse(errorsExists());
}
@Test(priority = 2)
public void test2() {
testSomething2();
Assert.assertFalse(errorsExists());
}
@Test(priority = 3)
public void test3() {
testSomething3();
Assert.assertFalse(errorsExists());
}
并且我想将 Assert.assertFalse(errorsExists())
移动到 BaseTestCase
或 TestListener
这样我就不必每次都在测试结束时通过它。
我试图将它移动到 TestsListener 到 onFinish
,但是方法 errorsExists()
需要驱动程序,我无法将其放入其中。
更新: 我想方法 errorsExists() 影响测试结果。假设在 test2 方法中 errorsExists return true -> 我想要得到以下结果: 测试1通过 测试 2 失败 测试 3 通过
据我所知,我不能将此方法用于任何 @After 注释,也不能将其用于 TestListener 中的 onTestFailure 或 onTestSuccess
您应该能够将其移至使用@AfterMethod 注释的新方法。任何用@AfterMethod 注解的方法都会在每个测试方法执行后执行。这样的事情应该有效:
@Test(priority = 1)
public void test1() {
testSomething1();
//Assert.assertFalse(errorsExists());
}
@Test(priority = 2)
public void test2() {
testSomething2;
//Assert.assertFalse(errorsExists());
}
@Test(priority = 3)
public void test3() {
testSomething3();
//Assert.assertFalse(errorsExists());
}
@AfterMethod
public void assertError() {
Assert.assertFalse(errorsExists());
}
如果您 运行 每个 @Test 方法是并行的,那么您可以通过以下方式实现。但前提是,每个 @Test 应该有自己的 WebDriver 实例。您可以使用 ThreadLocal 变量来实现这一点。例如:
public class Driver {
public static ThreadLocal<AppiumDriver> driver = new ThreadLocal<>();
public static AppiumDriver getDriver() {
return driver.get();
}
public synchronized void initalizeDriver(String deviceName, String platformVersion, String port, String udid) {
if (deviceName.contains("iPhone")) {
setIOSCapabilities(driver, deviceName, platformVersion, port, udid);
} else if (deviceName.equalsIgnoreCase("pcloudy-apple")) {
setPcloudyIOSCapabilties(driver,platformVersion);
} else {
if (deviceName.contains("R-")) {
setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
} else if (deviceName.equalsIgnoreCase("pcloudy-Android")) {
setPcloudyAndroidCapabilties(driver,platformVersion);
} else {
startAndroidEmulator(deviceName, udid);
setAndroidCapabilities(driver, deviceName, platformVersion, port, udid);
}
}
}
}
public void setAndroidCapabilities(ThreadLocal<AppiumDriver> driver, String device, String platformVersion, String port, String udid) {
try {
File sourceDir = new File("src");
File app = new File(sourceDir, ANDROID_APP_PATH);
DesiredCapabilities desiredCapabilties = new DesiredCapabilities();
desiredCapabilties.setCapability(MobileCapabilityType.DEVICE_NAME, device);
desiredCapabilties.setCapability(AndroidMobileCapabilityType.IGNORE_UNIMPORTANT_VIEWS,true);
driver.set(new AndroidDriver<>(new URL(APPIUM_DEFAULT_URL), desiredCapabilties));
} catch (Exception e) {
log.error(e.getMessage());
log.error("Exception in launching the Android Driver " + e);
e.printStackTrace();
}
}
基础中的方法class为每个@Test 方法启动一个新的驱动程序实例
@BeforeMethod(alwaysRun = true)
@Parameters(value={"deviceName","platformVersion","port","udid"})
public synchronized void executeBeforeTest(String deviceName, String platformVersion,
@Optional("Port Required") String port, @Optional("UDID Required") String udid){
Driver driverObj = new Driver();
Thread.currentThread().setName(deviceName);
driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
if(Driver.getDriver() == null) {
driverObj.initalizeDriver(deviceName,platformVersion,port,udid);
}
}
终于找到你要找的TestListener了class,
public class TestListener extends UITest implements ITestListener {
@Override
public void onTestFailure(ITestResult iTestResult) {
log.info("Driver getDriver() value is :: "+Driver.getDriver().toString());
log.info("Driver getSessionId() value is :: "+Driver.getDriver().getSessionId().toString());
if (Driver.getDriver() != null || Driver.getDriver().getSessionId() != null) {
try {
if (Driver.getDriver() instanceof IOSDriver) {
JavascriptExecutor js = (JavascriptExecutor) Driver.getDriver();
Map<String, Object> params = new HashMap<>();
params.put("bundleId", DeviceCapabalities.IOS_APP_BUNDLE_ID);
final Long state = (Long) js.executeScript("mobile: queryAppState", params);
System.out.println("Application state code is :" + state);
if (state == 1) {
log.error("Application has Crashed");
}
} else {
if (!(((AndroidDriver) (Driver.getDriver())).currentActivity().contains("app.name"))) {
log.error("Application has Crashed");
}
}
saveScreenshot(Driver.getDriver(),iTestResult);
} catch (Exception e) {
log.error("Exception :: " + e);
e.printStackTrace();
Assert.fail("Test case failed due to exception " + e);
}
}
}
您可以使用 IHookable
界面来实现。这通常(根据文档)用于在测试开始之前进行一些操作。但它也适用于每次测试结束时的操作。
创建一个实现此接口的 BaseTest
并让您的测试 类 扩展 BaseTest
。
public class BaseTest implements IHookable {
@Override
public void run(IHookCallBack cb, ITestResult testResult) {
cb.runTestMethod(testResult); // invokes the actual test case
Assert.assertFalse(errorsExists());
}
}
您可以调用一些代码并使用 IInvokedMethodListener
修改测试结果。
请注意,这是基于您的代码示例的非常简单的实现。 它可能需要一些改进。
测试Class:
@Listeners(ErrorsExistsListener.class)
class MyTest {
@Test(priority = 1)
public void test1() {
testSomething1();
}
@Test(priority = 2)
public void test2() {
testSomething2;
}
@Test(priority = 3)
public void test3() {
testSomething3();
}
boolean errorsExists() {
// some logic
}
}
测试监听器:
class ErrorsExistsListener implements IInvokedMethodListener {
@Override
void afterInvocation(IInvokedMethod method, ITestResult result) {
if (method.isTestMethod() && result.getStatus() != ITestResult.FAILURE) {
Object[] instances = result.getTestClass().getInstances(false);
MyTest myTestClass = (MyTest) instances[0]; // you'll get exception here if set this listener for non-MyTest class.
try {
Assert.assertFalse(myTestClass.errorsExists());
} catch (AssertionError e) {
result.setStatus(ITestResult.FAILURE);
result.setThrowable(e);
}
}
}
}