title: TestNG Annotations in a Superclass
body: <p>I am having some trouble with TestNG annotations, and I haven't found a good answer either on stackoverflow or in the testng documentation. What I'm trying to do is add a testng listener as well as parameters from a testng.xml file to a "test base" superclass. All testng tests will inherit the superclass. This will alleviate a lot of code redundancy in the testng test class files. But when I have the @Listeners and @Parameters annotation in the superclass, and not the class that contains the @Test method(s), the annotations do not work. In other words, the listener does not seem to "see" the tests, and the parameters from testng.xml do not get pulled in to the superclass during runtime.</p>
  
  <p>My "test base" (the superclass) has a testng listener from the <a href="https://saucelabs.com/java/se2/6" rel="nofollow">Sauce Labs</a> api that will listen for tests and update the success/failure of the test to Sauce Labs during remote execution. It also uses the @Parameters annotation to pull parameters from the current test run's testng.xml.</p>
  
  <p>TestBase superclass:</p>
  
  <pre><code>@Listeners(SauceOnDemandTestListener.class)
  public class TestBase implements SauceOnDemandSessionIdProvider, SauceOnDemandAuthenticationProvider {
      private SauceOnDemandAuthentication authentication;
      private DesiredCapabilities capabilities;
      protected ParallelWebDriver parallelWebDriver;
  
      @Parameters({"sauce_username", "sauce_accesskey", "platform", "browser", "version"})
      @BeforeClass(alwaysRun = true)
      public void setUp(String userName, String accessKey, String platform, String browser, String version) {   
          // Set up Sauce Auth
          if (userName != null &amp;&amp; accessKey != null) {
              this.authentication = new SauceOnDemandAuthentication(userName, accessKey);
          } else {
              this.authentication = new SauceOnDemandAuthentication();
          }
  
          // Set up the DesiredCapabilities
          if (platform != null) {
              this.capabilities.setCapability("platform", platform);
          } else {
              throw new NullArgumentException("[Parameter] platform does not exist or is not a valid value in testng.xml:");
          }
  
          if (browser != null) {
              this.capabilities.setCapability("browser", browser);
          } else {
              throw new NullArgumentException("[Parameter] browser does not exist or is not a valid value in testng.xml:");
          }
  
          if (version != null) {
              this.capabilities.setCapability("version", version);
          } else {
              throw new NullArgumentException("[Parameter] version does not exist or is not a valid value in testng.xml:");
          }
  
          // Set up the ParallelWebDriver for the test run
          parallelWebDriver = new ParallelWebDriver(new RemoteParallelDriver(), this.testingPlatform, capabilities);
          parallelWebDriver.setUserName(userName);
          parallelWebDriver.setAccessKey(accessKey);
      }
  
      @Override
      public String getSessionId() {
          SessionId sessionId = ((RemoteWebDriver)((WebDriver)parallelWebDriver.getDriver())).getSessionId();
          return (sessionId == null) ? null : sessionId.toString();
      }
  
      @Override
      public SauceOnDemandAuthentication getAuthentication() {
          return authentication;
      }
  }
  </code></pre>
  
  <p>Here is an example test class that inherits the TestBase.</p>
  
  <pre><code>public class SauceLabsRemote_Test extends TestBase {
      @BeforeTest
      public void testSetUp() throws MalformedURLException {
          parallelWebDriver.openBrowser();
      }
  
      public void searchGoogle(String searchText) throws InterruptedException {
          parallelWebDriver.getDriver().get("https://google.com");
          WebElement searchBox = parallelWebDriver.getDriver().findElement(By.id("gbqfq"));
          searchBox.sendKeys(searchText);
          WebElement searchButton = parallelWebDriver.getDriver().findElement(By.id("gbqfb"));
          searchButton.click();
  
          Assert.assertEquals(searchBox.getText(), "banjo");
      }
  
      @Test
      public void searchGoogle_Test1() throws InterruptedException {
          searchGoogle("banjo");
      }
  
      @Test
      public void searchGoogle_Test2() throws InterruptedException {
          searchGoogle("guitar");
      }
  
      @AfterTest
      public void testTearDown() {
          parallelWebDriver.closeBrowser();
      }
  }
  </code></pre>
  
  <p>And here is a mockup of my testng.xml.</p>
  
  <pre><code>&lt;suite name="Base Framework Unit Test Suite" verbose="1" &gt;   
  
      &lt;!-- Parameters required for Sauce Labs run --&gt;
      &lt;parameter name="sauce_username" value="testuser" /&gt;
      &lt;parameter name="sauce_accesskey" value="acc3-55k3y-t3st-t3st-t3st" /&gt;
  
      &lt;test name="Sauce Labs Remote Execution Test" &gt;
          &lt;parameter name="platform" value="OS X 10.6" /&gt;
          &lt;parameter name="browser" value="firefox" /&gt;
          &lt;parameter name="version" value="26" /&gt;
          &lt;classes&gt;
              &lt;class name="unittest.SauceLabsRemote_Test" /&gt;
          &lt;/classes&gt;
      &lt;/test&gt;
  
  &lt;/suite&gt;
  </code></pre>
  
  <p>So, is there any way to get TestNG's @Listeners and @Parameters to work on a superclass that does not contain @Test? Thanks in advance! And sorry for any bad coding practices; all this code was mocked up on-the-fly.</p>