├── README ├── build.gradle ├── lib ├── chromedriver ├── chromedriver.exe └── geckodriver └── src ├── main └── java │ ├── AbstractPageObject.java │ └── LandingPage.java └── test └── java ├── BaseTest.java └── ExampleTest.java /README: -------------------------------------------------------------------------------- 1 | This project is an example of building a test automation framework using WebDriver w Java, TestNG, Gradle with InteliJ or Eclipse. 2 | 3 | It extends the basic tutorial found on the Selenium Wiki and runs a couple of tests against Stack Overflow. 4 | 5 | http://code.google.com/p/selenium/wiki/GettingStarted 6 | http://code.google.com/p/selenium/wiki/PageObjects 7 | 8 | There are a couple of key concepts demonstrated in this project that will help you get started 9 | 10 | - Switching the navigation of the tests from one page object to another 11 | - Abstracting the test setup into a BaseTest class 12 | - Using TestNG and Gradle to run the tests 13 | 14 | Creating the IDE project 15 | ------------------------ 16 | 17 | InteliJ 18 | cd ~//page-objects 19 | ./gradlew idea 20 | 21 | Open the generated page-objects.ipr file and you're good to go. All your dependencies will be automatically resolved and ready to use. 22 | 23 | Eclipse 24 | cd ~//page-objects 25 | ./gradlew eclipse 26 | 27 | If you don't want to use Gradle you can also do this manually, as explained here by Simon Stewart aka The WebDriver guy. 28 | http://www.youtube.com/watch?v=Eft3qGFoqwE 29 | 30 | If you want to update the version of Selenium or TestNG you are using just update the version numbers in build.gradle and rerun the above commands to regenerate your project. 31 | 32 | Writing the Tests 33 | ----------------- 34 | 35 | I find using a Test Driven (Test) Development approach works well here. 36 | - Write the test 37 | - Create the Page Object Methods 38 | - Create the Page Object Locators 39 | - Run the test and debug until it passes 40 | 41 | Note also that the tests don't know anything about WebDriver .... keep it that way! 42 | 43 | Building the Page Objects 44 | ------------------------- 45 | 46 | You can use the PageFactory helper to define your locators 47 | 48 | http://code.google.com/p/selenium/wiki/PageFactory 49 | 50 | However, I prefer to store them as By objects 51 | 52 | There are several reasons for this: 53 | 54 | - The WebElement will get looked up each time you use the locator which can help avoid stale element exceptions 55 | - You can reuse your locators in methods that assert the presence or absence of a WebElement (return driver.findElements(yourByObjectLocator).size() > 0) 56 | - Personally I think they look cleaner in the code 57 | 58 | Running the tests via the IDE 59 | ----------------------------- 60 | 61 | Right click on the test and select 'run' or 'debug' 62 | 63 | Running the tests using Gradle 64 | ------------------------------ 65 | 66 | Unless you have Gradle installed, you'll need to use the Gradle wrapper which is included in the project 67 | ./gradlew or gradle.bat on Windows 68 | 69 | To run all tests (uses Firefox by default) 70 | ./gradlew clean test 71 | 72 | To run a single test class 73 | ./gradle clean test -Dtest.single="ExampleTest" 74 | 75 | To run only tests belonging to group 1 (as defined in the includegroup1 task in build.gradle) 76 | ./gradlew clean includegroup1 77 | 78 | To run only tests not belonging to group 1 (as defined in the excludegroup1 task in build.gradle) 79 | ./gradlew clean excludegroup1 80 | 81 | To run tests in Chrome 82 | ./gradle clean test -DBROWSER=chrome 83 | 84 | To run tests in IE 85 | gradle.bat clean test -DBROWSER=internetExplorer 86 | 87 | 88 | 89 | All and any feedback welcome and appreciated, I'm still learning too. 90 | @iainrose -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | apply plugin: 'idea' 3 | apply plugin: 'eclipse' 4 | 5 | repositories { 6 | mavenCentral() 7 | } 8 | 9 | dependencies { 10 | compile "org.seleniumhq.selenium:selenium-java:3.141.59" 11 | compile "org.testng:testng:6.10" 12 | } 13 | 14 | tasks.withType(Test) { 15 | useTestNG() 16 | systemProperties = System.getProperties() 17 | maxParallelForks = 2 18 | } 19 | 20 | task includegroup1(type: Test) { 21 | useTestNG() { 22 | includeGroups 'group1' 23 | } 24 | } 25 | 26 | task excludegroup1(type: Test) { 27 | useTestNG() { 28 | excludeGroups 'group1' 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /lib/chromedriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iainrose/page-objects/bea5313bf3b072c971a24eedce7ecd8d36aff451/lib/chromedriver -------------------------------------------------------------------------------- /lib/chromedriver.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iainrose/page-objects/bea5313bf3b072c971a24eedce7ecd8d36aff451/lib/chromedriver.exe -------------------------------------------------------------------------------- /lib/geckodriver: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iainrose/page-objects/bea5313bf3b072c971a24eedce7ecd8d36aff451/lib/geckodriver -------------------------------------------------------------------------------- /src/main/java/AbstractPageObject.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.By; 2 | import org.openqa.selenium.WebDriver; 3 | import org.openqa.selenium.WebElement; 4 | import org.openqa.selenium.support.ui.ExpectedConditions; 5 | import org.openqa.selenium.support.ui.WebDriverWait; 6 | import org.testng.Assert; 7 | 8 | import java.util.List; 9 | 10 | public abstract class AbstractPageObject { 11 | 12 | protected WebDriver driver; 13 | protected WebDriverWait wait; 14 | 15 | public AbstractPageObject(WebDriver driver) { 16 | this.driver = driver; 17 | this.wait = (new WebDriverWait(driver, 30)); 18 | isLoaded(); 19 | } 20 | 21 | // Each page object must implement this method to return the identifier of a unique WebElement on that page. 22 | // The presence of this unique element will be used to assert that the expected page has finished loading 23 | protected abstract By getUniqueElement(); 24 | 25 | protected void isLoaded() throws Error { 26 | //Define a list of WebElements that match the unique element locator for the page 27 | List uniqueElement = driver.findElements(getUniqueElement()); 28 | 29 | // Assert that the unique element is present in the DOM 30 | Assert.assertTrue((uniqueElement.size() > 0), 31 | "Unique Element \'" + getUniqueElement().toString() + "\' not found for " + this.getClass().getSimpleName()); 32 | 33 | // Wait until the unique element is visible in the browser and ready to use. This helps make sure the page is 34 | // loaded before the next step of the tests continue. 35 | wait.until(ExpectedConditions.visibilityOfElementLocated(getUniqueElement())); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/LandingPage.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.By; 2 | import org.openqa.selenium.WebDriver; 3 | import org.openqa.selenium.WebElement; 4 | import org.openqa.selenium.support.ui.ExpectedConditions; 5 | import org.testng.Assert; 6 | 7 | import java.util.List; 8 | 9 | public class LandingPage extends AbstractPageObject { 10 | 11 | public LandingPage(WebDriver driver) { 12 | super(driver); 13 | } 14 | 15 | By searchButtonLocator = By.cssSelector("[value=\"Google Search\"]"); 16 | 17 | @Override 18 | protected By getUniqueElement() { 19 | return By.cssSelector("[name=q]"); 20 | } 21 | 22 | public Boolean isSearchButtonDisplayed() { 23 | List searchButton = driver.findElements(searchButtonLocator); 24 | return searchButton.size() > 0; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/test/java/BaseTest.java: -------------------------------------------------------------------------------- 1 | import org.openqa.selenium.WebDriver; 2 | import org.openqa.selenium.chrome.ChromeDriver; 3 | import org.openqa.selenium.firefox.FirefoxDriver; 4 | import org.openqa.selenium.ie.InternetExplorerDriver; 5 | import org.openqa.selenium.remote.DesiredCapabilities; 6 | import org.openqa.selenium.remote.LocalFileDetector; 7 | import org.openqa.selenium.remote.RemoteWebDriver; 8 | import org.testng.annotations.AfterClass; 9 | import org.testng.annotations.AfterMethod; 10 | import org.testng.annotations.BeforeClass; 11 | import org.testng.annotations.BeforeMethod; 12 | 13 | import java.net.MalformedURLException; 14 | import java.net.URL; 15 | import java.util.concurrent.TimeUnit; 16 | 17 | public class BaseTest { 18 | 19 | protected static final String WEB_SERVER = System.getProperty("WEB_SERVER", "http://google.com/"); 20 | protected static final String BROWSER = System.getProperty("BROWSER", "chrome"); 21 | protected static final boolean REMOTE_DRIVER = Boolean.valueOf(System.getProperty("REMOTE_DRIVER", "false")); 22 | protected static final String SELENIUM_HOST = System.getProperty("SELENIUM_HOST", "localhost"); 23 | protected static final int SELENIUM_PORT = Integer.valueOf(System.getProperty("SELENIUM_PORT", "4444")); 24 | 25 | public static RemoteWebDriver driver; 26 | 27 | @BeforeClass(alwaysRun = true) 28 | public void setupWebDriver() throws MalformedURLException { 29 | if (REMOTE_DRIVER) { 30 | setupRemoteDriver(); 31 | driver.setFileDetector(new LocalFileDetector()); 32 | } else { 33 | setupLocalDriver(); 34 | } 35 | driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS); 36 | } 37 | 38 | private void setupLocalDriver() { 39 | 40 | switch (BROWSER) { 41 | case "firefox": 42 | String geckoDriverPath = "lib/geckodriver"; 43 | System.setProperty("webdriver.gecko.driver", geckoDriverPath); 44 | driver = new FirefoxDriver(); 45 | break; 46 | case "chrome": 47 | String chromeDriverPath; 48 | if (System.getProperty("os.name").contains("Windows")) { 49 | chromeDriverPath = "lib/chromedriver.exe"; 50 | } else { 51 | chromeDriverPath = "lib/chromedriver"; 52 | } 53 | System.setProperty("webdriver.chrome.driver", chromeDriverPath); 54 | driver = new ChromeDriver(); 55 | break; 56 | case "internetExplorer": 57 | DesiredCapabilities capabilities = DesiredCapabilities.internetExplorer(); 58 | capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); 59 | driver = new InternetExplorerDriver(capabilities); 60 | default: 61 | throw new RuntimeException("Browser type unsupported"); 62 | } 63 | } 64 | 65 | private void setupRemoteDriver() throws MalformedURLException { 66 | DesiredCapabilities capabilities; 67 | if (BROWSER.equals("firefox")) { 68 | capabilities = DesiredCapabilities.firefox(); 69 | } else if (BROWSER.equals("internetExplorer")) { 70 | capabilities = DesiredCapabilities.internetExplorer(); 71 | capabilities.setCapability(InternetExplorerDriver.INTRODUCE_FLAKINESS_BY_IGNORING_SECURITY_DOMAINS, true); 72 | } else if (BROWSER.equals("chrome")) { 73 | capabilities = DesiredCapabilities.chrome(); 74 | } else { 75 | throw new RuntimeException("Browser type unsupported"); 76 | } 77 | driver = new RemoteWebDriver( 78 | new URL("http://" + SELENIUM_HOST + ":" + SELENIUM_PORT + "/wd/hub"), 79 | capabilities); 80 | } 81 | 82 | @BeforeMethod(alwaysRun = true) 83 | public void loadWebApplication() { 84 | driver.get(WEB_SERVER); 85 | } 86 | 87 | @AfterMethod(alwaysRun = true) 88 | public void deleteAllCookies() { 89 | driver.manage().deleteAllCookies(); 90 | } 91 | 92 | @AfterClass(alwaysRun = true) 93 | public void suiteTearDown() { 94 | driver.quit(); 95 | } 96 | 97 | } -------------------------------------------------------------------------------- /src/test/java/ExampleTest.java: -------------------------------------------------------------------------------- 1 | import org.testng.Assert; 2 | import org.testng.annotations.Test; 3 | 4 | public class ExampleTest extends BaseTest { 5 | 6 | public ExampleTest() { 7 | super(); 8 | } 9 | 10 | @Test(groups = {"group1"}) 11 | public void verifyGoogleSearchDisplayed() { 12 | LandingPage landingPage = new LandingPage(driver); 13 | Assert.assertTrue(landingPage.isSearchButtonDisplayed()); 14 | } 15 | 16 | } 17 | 18 | --------------------------------------------------------------------------------