0

I am struggling with declaring a parameter at class level with testNG. I have a browser parameter that works fine when declared at the method level.

Because I am mapping the test to a cucumber step definition and will be declaring a url parameter at the method level, I want to take the browser parameter away from the method to the class (global) level. So, in the xml file, I moved the browser parameter from test level to the suite level like this:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">


<suite name="Suite" parallel="tests" thread-count="5">

    <!-- Parametter moved to suite level -->
    <parameter name="Browser" value="CHROME"/>
    <parameter name="Browser" value="FF"/>

    <test name="Chrome Test">
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>

    
    <test name="Firefox Test">
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>
</suite>

Then in the test class, I removed the browser parameter from the method and to the class and declared browser as public static. Sadly, the browser could not be found at runtime, resulting in a NullPointerException:

@Parameters("Browser") //parameter declared at class level
public class WebTest {


  WebDriver driver = null;
  BasePageWeb basePage;
  public static String browser; //class variable


  @BeforeClass
  public void navigateToUrl() {
    switch (browser) { //NullpointerException thrown here

      case "CHROME":
        WebDriverManager.chromedriver().setup();
        driver = new ChromeDriver();
        break;

      case "FF":
        WebDriverManager.firefoxdriver().setup();
        driver = new FirefoxDriver();
        break;

      default:
        driver = null;
        break;
    }
    driver.get("www.google.com");

  }

How do I declare the browser parameter successfully at class level?

The man
  • 129
  • 16

1 Answers1

1

For Parameters annotation METHOD, CONSTRUCTOR, TYPE target ElementTypes defined.

@Retention(RUNTIME)
@Target({METHOD, CONSTRUCTOR, TYPE})
public @interface Parameters {|
...

TYPE means it might be defined on class level.

And I've tried to find any example with such usage and also tried to make it work myself (also trying to assign to a static variable).

But no luck..

So I can suggest just this alternative (define @Parameter for CONSTRUCTOR):

public class WebTest {

   public String browser;

   @Parameters({ "Browser" })
   public WebTest(String browser) {
       this.browser = browser;
   }

...
}

and xml seems to be:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">


<suite name="Suite" parallel="tests" thread-count="5">

    <test name="Chrome Test">
        <parameter name="Browser" value="CHROME"/>
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>

    
    <test name="Firefox Test">
        <parameter name="Browser" value="FF"/>
        <classes>
            <class name="tests.web.WebTest"/>
        </classes>
    </test>
</suite>
Max Daroshchanka
  • 2,698
  • 2
  • 10
  • 14
  • 1
    This was cleverly implemented. Well done! If I want to create an object of the `WebTest ` class in another class, how do I achieve that? I tried this: `private final WebTest webTest = new WebTest();` but I got a compilation error: `WebTest(java.lang.String)' in 'tests.web.WebTest' cannot be applied to '()'` – The man Feb 08 '22 at 15:10
  • `private final WebTest webTest = new WebTest("FF");` or `private final WebTest webTest = new WebTest("CHROME");` – Max Daroshchanka Feb 08 '22 at 15:16
  • if I create the object of the class from another class, this way `private final WebTest webTest = new WebTest("FF")`, and call the `webTest.navigateToUrl(url)` method, test runs only in Firefox. If I do `private final WebTest webTest = new WebTest("CHROME")`, it runs only in Chrome. The test no longer runs in both browsers. What could be wrong? – The man Feb 12 '22 at 15:02
  • @Theman if you want to have the parametrization, applied for `private final WebTest webTest`, your owner class should already know the browser parameter value, and pass it to the `WebTest` constructor. And I suggest to initialize the `webTest` variable in owner class constructor. In this way I can imagine how the owner class got the browser variable from TestNG xml and apply it to `WebTest`. Your original question doesn't mention the context when you have the test class as a variable of some other class. So, I cannot fully imagine your use case. – Max Daroshchanka Feb 12 '22 at 15:37
  • This is the example ```public class OwnerTest { private final WebTest webTest; @Parameters({ "Browser" }) public OwnerTest(String browser) { webTest = new WebTest(browser); } ... }``` – Max Daroshchanka Feb 12 '22 at 15:40
  • 1
    You are right. The full context wasnt captured. Take a look at [this question](https://stackoverflow.com/questions/71093267/can-a-testng-cross-browser-test-be-executed-with-cucumber-runner) for the bigger picture. Your input so far has been very helpful – The man Feb 12 '22 at 15:53
  • Does the new question make more sense to you? – The man Feb 12 '22 at 19:31
  • @Theman, sure! I'll help you soon! The new context is really helpful. – Max Daroshchanka Feb 12 '22 at 19:32
  • @Theman, please check https://stackoverflow.com/questions/71093267/can-a-testng-cross-browser-test-be-executed-with-cucumber-runner. – Max Daroshchanka Feb 12 '22 at 20:00