Search code examples
javaseleniumtestngappium

How can I use @BeforeTest for Capabilities class / or correctly extends on each @Test


I would like to create one class in which to insert @BeforeTest Capabilities. Referencing the below code, it is easy to insert tests into @Test. Without TestNG everything works, but it doesn't work with TestNG. Maybe I misunderstood something?

Class with Capabilities

public class test {

        public static AndroidDriver<AndroidElement> Capabilities() throws MalformedURLException {

            File f =new File("src");
            File fs = new File(f,"ApiDemos-debug.apk");
            DesiredCapabilities capabilities = new DesiredCapabilities();

            capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "demo");
            capabilities.setCapability(MobileCapabilityType.APP, fs.getAbsolutePath());
            AndroidDriver<AndroidElement> driver= new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"),capabilities);

             return driver;
        }

Test example with extends Capabilities From test

public class swiping extends test {

    public static void main(String[] args) throws MalformedURLException, InterruptedException {
        AndroidDriver<AndroidElement> driver=Capabilities();
        driver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);        
        driver.findElementByXPath("//android.widget.TextView[@text='Views']").click();

        driver.findElementByXPath("//android.widget.TextView[@text='Date Widgets']").click();

        driver.findElementByAndroidUIAutomator("text(\"2. Inline\")").click();

        driver.findElementByXPath("//*[@content-desc='9']").click();

         Thread.sleep(1000);

        TouchAction t=new TouchAction(driver);

        WebElement first=driver.findElementByXPath("//*[@content-desc='15']");
        WebElement second=driver.findElementByXPath("//*[@content-desc='45']");
        t.longPress(longPressOptions().withElement(element(first)).withDuration(ofSeconds(2))).moveTo(element(second)).release().perform();
    }

}

Solution

  • The below example shows a TestNG example of how to do the same thing.

    The example leverages ThreadLocal so that tomorrow if you decide to run multiple @Test methods in parallel wherein every @Test method needs its own AndroidDriver instance, this would still work.

    import static io.appium.java_client.touch.LongPressOptions.longPressOptions;
    import static io.appium.java_client.touch.offset.ElementOption.element;
    import static java.time.Duration.ofSeconds;
    
    import io.appium.java_client.TouchAction;
    import io.appium.java_client.android.AndroidDriver;
    import io.appium.java_client.remote.MobileCapabilityType;
    import java.io.File;
    import java.net.MalformedURLException;
    import java.net.URL;
    import java.util.concurrent.TimeUnit;
    import org.openqa.selenium.WebElement;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import org.testng.annotations.AfterMethod;
    import org.testng.annotations.BeforeMethod;
    import org.testng.annotations.Test;
    
    public class TestClassExample {
    
      //We use thread local so that even if you decide to run tests in parallel, every @Test method
      //will get its own AndroidDriver instance
      private static final ThreadLocal<AndroidDriver> drivers = new ThreadLocal<>();
    
      @BeforeMethod
      public void setupDriver() throws MalformedURLException {
        File f = new File("src");
        File fs = new File(f, "ApiDemos-debug.apk");
        DesiredCapabilities capabilities = new DesiredCapabilities();
    
        capabilities.setCapability(MobileCapabilityType.DEVICE_NAME, "demo");
        capabilities.setCapability(MobileCapabilityType.APP, fs.getAbsolutePath());
        AndroidDriver driver =
            new AndroidDriver<>(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);
        drivers.set(driver);
      }
    
      @AfterMethod
      public void cleanupDriver() {
        drivers.get().quit();
        drivers.remove();
      }
    
      @Test
      public void testMethod() throws InterruptedException {
        AndroidDriver driver = drivers.get();
        driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
        driver.findElementByXPath("//android.widget.TextView[@text='Views']").click();
    
        driver.findElementByXPath("//android.widget.TextView[@text='Date Widgets']").click();
    
        driver.findElementByAndroidUIAutomator("text(\"2. Inline\")").click();
    
        driver.findElementByXPath("//*[@content-desc='9']").click();
    
        Thread.sleep(1000);
    
        TouchAction t = new TouchAction(driver);
    
        WebElement first = driver.findElementByXPath("//*[@content-desc='15']");
        WebElement second = driver.findElementByXPath("//*[@content-desc='45']");
        t.longPress(longPressOptions().withElement(element(first)).withDuration(ofSeconds(2)))
            .moveTo(element(second))
            .release()
            .perform();
      }
    }
    

    PS: You should not be using @BeforeTest because that gets executed only once per <test> tag. You are better off using either a @BeforeClass (which gets executed once per test class (or) a @BeforeMethod (which gets executed once per @Test method)