[英]TestNG - how to run the same method at the end of each test
I have something like:我有类似的东西:
@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());
}
and I would like to move Assert.assertFalse(errorsExists())
to BaseTestCase
or to TestListener
so I will not have to pass it every time at the end of the test.我想将
Assert.assertFalse(errorsExists())
移动到BaseTestCase
或TestListener
,这样我就不必每次在测试结束时都通过它。 I tried to move it to TestsListener to onFinish
but method errorsExists()
requires driver and I have problems to get it in there.我试图将它移到 TestsListener 到
onFinish
但方法errorsExists()
需要驱动程序,我有问题将它放在那里。
Update: I want to method errorsExists() influence test result.更新:我想方法 errorsExists() 影响测试结果。 Lets say that in test2 method errorsExists return true -> I want to have following results: test1 passed test2 failed test3 passed
假设在 test2 方法中 errorsExists 返回 true -> 我想得到以下结果: test1 通过 test2 failed test3 通过
so as far as I know I cannot put this method to any @After annotations and I cannot put it to onTestFailure or onTestSuccess in TestListener据我所知,我不能将此方法放在任何 @After 注释中,也不能将其放在 TestListener 中的 onTestFailure 或 onTestSuccess
You should be able to move it to a new method annotated with @AfterMethod.您应该能够将其移至使用 @AfterMethod 注释的新方法。 Any method annotated with @AfterMethod will be executed after each test method is executed.
任何带有@AfterMethod 注解的方法都将在每个测试方法执行后执行。 Something like this should work:
像这样的东西应该工作:
@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());
}
If you are running each of your @Test methods in parallel, then you can achieve this in the following way.如果您并行运行每个 @Test 方法,则可以通过以下方式实现此目的。 But the pre-requisite is, each @Test should have its own WebDriver instance.
但前提是,每个 @Test 都应该有自己的 WebDriver 实例。 You can use ThreadLocal variable to achieve this.
您可以使用 ThreadLocal 变量来实现这一点。 Eg:
例如:
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();
}
}
Method inside the base class to start a new driver instance for each @Test method基础 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);
}
}
Finally the TestListener class you are looking for,最后是您正在寻找的 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);
}
}
}
You may use the IHookable
interface to achieve this.您可以使用
IHookable
接口来实现这一点。 This is usually (according to the documentation), used to do some operations before the test start.这通常是(根据文档),用于在测试开始之前做一些操作。 But it works fine for operations at the end of each test as well.
但它也适用于每次测试结束时的操作。
Create a BaseTest
which implements this interface and let your test classes extend the BaseTest
.创建一个实现此接口的
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());
}
}
You can invoke some code and modify test results using IInvokedMethodListener
.您可以使用
IInvokedMethodListener
调用一些代码并修改测试结果。
Note, that this is a very simple implementation just based on your code example.请注意,这是一个非常简单的实现,仅基于您的代码示例。 It may need some improvements.
它可能需要一些改进。
Test Class:测试 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
}
}
Test Listener:测试监听器:
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);
}
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.