Skip to content

Latest commit

 

History

History
150 lines (119 loc) · 10.4 KB

JUnit4Support.md

File metadata and controls

150 lines (119 loc) · 10.4 KB

Introduction

In addition to its TestNG support, Selenium Foundation also includes support for JUnit 4. This support is built upon JUnit Foundation, which provides the framework for method interception (used for driver management), artifact capture (used to acquire screenshots and page source), and automatic retry of failed tests.

JUnit 4 Required Configuration

  • Add the JUnit Foundation Java agent to your project's test configuration.
    • NOTE: The -javaagent specification you add to your project configuration may not be active in all contexts. For example, you'll probably find that this option must also be added to your IDE run/debug configurations.
  • Add a service loader run watcher configuration file in your project's resources/META-INF/services folder:
com.nordstrom.automation.junit.JUnitWatcher
com.nordstrom.automation.selenium.junit.DriverListener
com.nordstrom.automation.selenium.junit.DriverWatcher

JUnit 4 Required Elements

There are several required elements that must be included in every JUnit 4 test class to activate the features of Selenium Foundation. To assist you in this process, we've included the JUnitBase class as a starter. This class includes all of the required elements outlined below.

JUnitBase is an abstract class that implements the TestBase interface, which provides a common abstraction for both TestNG and JUnit 4 tests.

Outline of Required Elements

The following is an outline of the elements that must be included in every JUnit 4 project that uses Selenium Foundation:

  • JUnit Foundation event notifications:
    The JUnit support provided by Selenium Foundation relies on event notifications published by JUnit Foundation. Notifications are enabled by a Java agent, which uses bytecode enhancement to install hooks on test and configuration methods.
Maven configuration for Java agent:
    <plugins>
      <!-- This provides the path to the Java agent -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>3.1.1</version>
        <executions>
          <execution>
            <id>getClasspathFilenames</id>
            <goals>
              <goal>properties</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.22.0</version>
        <configuration>
          <argLine>-javaagent:${com.nordstrom.tools:junit-foundation:jar}</argLine>
        </configuration>
      </plugin>
    </plugins>
Gradle configuration for Java agent:
test {
    jvmArgs "-javaagent:${classpath.find { it.name.contains('junit-foundation') }.absolutePath}"
}
Gradle configuration (Android Studio):
android {
    testOptions {
        unitTests.all {
            jvmArgs "-javaagent:${classpath.find { it.name.contains('junit-foundation') }.absolutePath}"
        }
    }
}
  • DriverWatcher:
    Activated by the service loader configuration specified above, DriverWatcher implements the JUnit Foundation MethodWatcher interface to manage driver sessions. It provides initial page support, and it also supplies a JUnit 4 TestWatcher:
    • DriverWatcher.getTestWatcher():
      The test rule returned by this static method is responsible for closing the driver attached to the current test method.
  • DriverListener:
    Activated by the service loader configuration specified above, DriverListener implements the JUnit Foundation ShutdownListener interface to shut down the local Selenium Grid servers at the end of the run.
  • Rule:
    Several core features of Selenium Fondation are implemented as TestWatcher rules, and these must be applied in a specific order. As of JUnit 4.13, the Rule annotation provides an order attribute to control the order in which rules are applied. The JUnitBase class declares the following three watcher in order (outer to inner):
    • DriverWatcher:
      As described previously, the test watcher returned by DriverWatcher.getTestWatcher() closes the driver attached to the current test method.
    • PageSourceCapture:
      PageSourceCapture is a JUnit 4 test watcher that automatically captures page source in the event of test failures.
    • ScreenshotCapture:
      ScreenshotCapture is a JUnit 4 test watcher that automatically captures a screenshot in the event of test failure.

NOTE: Prior to JUnit 4.13, rule ordering was achieved via the RuleChain class. You can see how this looked here.

Automatic Retry of Failed Tests

Selenium Foundation includes an implementation of the JUnitRetryAnalyzer interface of JUnit Foundation. This retry analyzer considers any test that fails due to a WebDriverException to be retriable. By default, this retry analyzer is disabled. To enable automatic retry of WebDriverException failures:

  • Add a service loader retry analyzer configuration file in the META-INF/services folder:
com.nordstrom.automation.junit.JUnitRetryAnalyzer
com.nordstrom.automation.selenium.junit.RetryAnalyzer
  • Specify a positive value for the MAX_RETRY setting of JUnit Foundation:
junit.properties
junit.max.retry=2

In this example, these two configurations will enable JUnit Foundation to retry tests that fail with WebDriverException twice before counting them as failures. See the JUnit Foundation documentation for more details.

Demonstrated Features

The JUnitBase class demonstrates several features of the Selenium Foundation API:

  • TestBase.optionalOf(Object):
    This static utility method wraps the specified object in an Optional object. If the object to be wrapped is 'null', this method returns an empty optional.
  • ScreenshotCapture.getAtomIdentity():
    This instance method of ScreenshotCapture enables test code to acquire the AtomIdentity object for the current JUnit 4 test method. This object can be interrogated for many useful propeties of the test method, including test class instance, Description object, and instance parameters.
  • ScreenshotCapture.getDescription():
    This instance method of ScreenshotCapture enables test code to acquire the Description object for the current JUnit 4 test method. This object can be interrogated for many useful propeties of the test method, including method name, attached annotations, and containing class.

Driver Acquisition and Hand-Off

In the preceding section, driver sessions are acquired automatically for each test or requested implicitly by applying the @InitialPage annotation. The core functionality used to initiate driver sessions implicitly can also be invoked ad hoc to acquire drivers explicitly:

WebDriver driver = GridUtility.getDriver();

This method uses the configured settings for Selenium Grid and desired browser from the current test execution context to instantiate a new driver session.

If the @InitialPage annotation is applied to a @Before configuration method, the driver instantiated for this method is automatically handed off to the test that follows. The initial page as specified for the configuration method is handed off as well. If actions performed by your configuration method trigger page transitions, you need to store the final page accessed by the configuration method as the initial page for the test method:

@Before
@InitialPage(LoginPage.class)
public void logInBeforeTest() {
    LoginPage loginPage = getInitialPage();
    MainMenuPage mainMenuPage = loginPage.logInAs(USER.StandardUser);
    // update initial page for test method
    setInitialPage(mainMenuPage);
}

@Test
public void testMenuFeatures() {
    MainMenuPage mainMenuPage = getInitialPage();
    ...
}

Written with StackEdit.