├── .gitignore ├── LICENSE ├── README.md ├── pom.xml └── src └── test ├── java ├── pages │ ├── BasePage.java │ ├── HomePage.java │ ├── LoginPage.java │ └── PageGenerator.java ├── tests │ ├── BaseTest.java │ ├── CopyOfLoginTest.java │ └── LoginTest.java └── utils │ ├── ChromeOps.java │ └── LogUtil.java └── resources └── junit-platform.properties /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | *.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # Intellij 26 | .idea/ 27 | *.iml 28 | 29 | # Maven output 30 | target/ 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 SW Test Academy 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # junit5-parallel-testing 2 | Junit 5 parallel test execution 3 | Here is the detailed article link for JUnit 5 Parallel Test Execution: 4 | 5 | https://www.swtestacademy.com/junit5-parallel-test-execution/ 6 | 7 | To run the tests with maven please use this command: mvn clean -Dtest=tests.** test -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | junit5-parallel 8 | junit5-parallel 9 | 1.0-SNAPSHOT 10 | 11 | 12 | 13 | org.seleniumhq.selenium 14 | selenium-java 15 | 4.0.0-beta-3 16 | 17 | 18 | 19 | org.junit.jupiter 20 | junit-jupiter-api 21 | 5.8.0-M1 22 | test 23 | 24 | 25 | 26 | org.junit.jupiter 27 | junit-jupiter-engine 28 | 5.8.0-M1 29 | 30 | 31 | 32 | org.junit.platform 33 | junit-platform-launcher 34 | 1.8.0-M1 35 | test 36 | 37 | 38 | 39 | 40 | 41 | 42 | org.apache.maven.plugins 43 | maven-surefire-plugin 44 | 2.22.2 45 | 46 | plain 47 | 48 | 49 | 50 | org.apache.maven.plugins 51 | maven-compiler-plugin 52 | 53 | 11 54 | 11 55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /src/test/java/pages/BasePage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import java.time.Duration; 4 | import java.util.List; 5 | import org.openqa.selenium.By; 6 | import org.openqa.selenium.JavascriptExecutor; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.support.ui.ExpectedConditions; 10 | import org.openqa.selenium.support.ui.WebDriverWait; 11 | 12 | public class BasePage extends PageGenerator { 13 | WebDriverWait wait; 14 | JavascriptExecutor js; 15 | 16 | public BasePage(WebDriver driver) { 17 | super(driver); 18 | wait = new WebDriverWait(driver, Duration.ofSeconds(10)); 19 | js = (JavascriptExecutor) driver; 20 | } 21 | 22 | //Click Method by using JAVA Generics (You can use both By or Webelement) 23 | public void click(T elementAttr) { 24 | if (elementAttr.getClass().getName().contains("By")) { 25 | driver.findElement((By) elementAttr).click(); 26 | } else { 27 | ((WebElement) elementAttr).click(); 28 | } 29 | } 30 | 31 | public void jsClick(By by) { 32 | js.executeScript("arguments[0].click();", wait.until(ExpectedConditions.visibilityOfElementLocated(by))); 33 | } 34 | 35 | //Write Text by using JAVA Generics (You can use both By or Webelement) 36 | public void writeText(T elementAttr, String text) { 37 | if (elementAttr.getClass().getName().contains("By")) { 38 | driver.findElement((By) elementAttr).sendKeys(text); 39 | } else { 40 | ((WebElement) elementAttr).sendKeys(text); 41 | } 42 | } 43 | 44 | //Read Text by using JAVA Generics (You can use both By or Webelement) 45 | public String readText(T elementAttr) { 46 | if (elementAttr.getClass().getName().contains("By")) { 47 | return driver.findElement((By) elementAttr).getText(); 48 | } else { 49 | return ((WebElement) elementAttr).getText(); 50 | } 51 | } 52 | 53 | //Close popup if exists 54 | public void handlePopup(By by) throws InterruptedException { 55 | List popup = driver.findElements(by); 56 | if (!popup.isEmpty()) { 57 | popup.get(0).click(); 58 | Thread.sleep(200); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/pages/HomePage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.WebElement; 5 | import org.openqa.selenium.support.FindBy; 6 | import org.openqa.selenium.support.How; 7 | import org.openqa.selenium.support.PageFactory; 8 | 9 | public class HomePage extends BasePage { 10 | 11 | //*********Constructor********* 12 | public HomePage(WebDriver driver) { 13 | super(driver); 14 | } 15 | 16 | //*********Page Variables********* 17 | String baseURL = "http://www.n11.com/"; 18 | 19 | //*********Web Elements By Using Page Factory********* 20 | @FindBy(how = How.CLASS_NAME, using = "btnSignIn") 21 | public WebElement signInButton; 22 | 23 | //*********Page Methods********* 24 | //Go to Homepage 25 | public HomePage givenIAmAtHomePage() { 26 | driver.get(baseURL); 27 | return this; 28 | } 29 | 30 | //Go to LoginPage 31 | public LoginPage whenIGoToLoginPage() { 32 | click(signInButton); 33 | return new PageFactory().initElements(driver, LoginPage.class); 34 | } 35 | } -------------------------------------------------------------------------------- /src/test/java/pages/LoginPage.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; 4 | import static org.junit.jupiter.api.Assertions.assertTrue; 5 | 6 | import org.openqa.selenium.By; 7 | import org.openqa.selenium.WebDriver; 8 | import org.openqa.selenium.WebElement; 9 | import org.openqa.selenium.support.FindBy; 10 | import org.openqa.selenium.support.How; 11 | import utils.LogUtil; 12 | 13 | public class LoginPage extends BasePage { 14 | 15 | //*********Constructor********* 16 | public LoginPage(WebDriver driver) { 17 | super(driver); 18 | } 19 | 20 | //*********Web Elements by using Page Factory********* 21 | @FindBy(how = How.ID, using = "email") 22 | public WebElement userName; 23 | 24 | @FindBy(how = How.ID, using = "password") 25 | public WebElement password; 26 | 27 | By loginButton = By.id("loginButton"); 28 | By errorMessageUsernameBy = By.xpath("//*[@id=\"loginForm\"]/div[1]/div/div"); 29 | By errorMessagePasswordBy = By.xpath("//*[@id=\"loginForm\"]/div[2]/div/div"); 30 | 31 | //*********Page Methods********* 32 | public LoginPage andILoginToN11(String userName, String password) { 33 | writeText(this.userName, userName); 34 | writeText(this.password, password); 35 | jsClick(loginButton); 36 | return this; 37 | } 38 | 39 | public LoginPage thenIVerifyLoginUserNameErrorMessage(String expectedText) { 40 | assertEquals(expectedText, readText(errorMessageUsernameBy)); 41 | return this; 42 | } 43 | 44 | public LoginPage thenIVerifyPasswordErrorMessage(String expectedText) { 45 | assertEquals(expectedText, readText(errorMessagePasswordBy)); 46 | return this; 47 | } 48 | 49 | public LoginPage thenIVerifyLogEntryFailMessage() { 50 | assertTrue(LogUtil.isLoginErrorLog(driver)); 51 | return this; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /src/test/java/pages/PageGenerator.java: -------------------------------------------------------------------------------- 1 | package pages; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.support.PageFactory; 5 | 6 | public class PageGenerator { 7 | public WebDriver driver; 8 | 9 | public PageGenerator(WebDriver driver) { 10 | this.driver = driver; 11 | } 12 | 13 | //JAVA Generics to Create and return a New Page 14 | public TPage getPage(Class pageClass) { 15 | //Initialize the Page with its elements and return it. 16 | return PageFactory.initElements(driver, pageClass); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/test/java/tests/BaseTest.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import java.time.Duration; 4 | import org.junit.jupiter.api.AfterEach; 5 | import org.junit.jupiter.api.BeforeEach; 6 | import org.openqa.selenium.WebDriver; 7 | import org.openqa.selenium.chrome.ChromeDriver; 8 | import org.openqa.selenium.support.ui.WebDriverWait; 9 | import pages.PageGenerator; 10 | 11 | public class BaseTest { 12 | public WebDriver driver; 13 | public WebDriverWait wait; 14 | public PageGenerator page; 15 | 16 | @BeforeEach 17 | public void classLevelSetup() { 18 | driver = new ChromeDriver(); 19 | wait = new WebDriverWait(driver, Duration.ofSeconds(10)); 20 | page = new PageGenerator(driver); 21 | } 22 | 23 | @AfterEach 24 | public void teardown() { 25 | driver.quit(); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/test/java/tests/CopyOfLoginTest.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.parallel.Execution; 5 | import org.junit.jupiter.api.parallel.ExecutionMode; 6 | import pages.HomePage; 7 | 8 | @Execution(ExecutionMode.CONCURRENT) 9 | public class CopyOfLoginTest extends BaseTest { 10 | @Test 11 | public void invalidLoginTest_InvalidUserNameInvalidPassword2() { 12 | page.getPage(HomePage.class) 13 | .givenIAmAtHomePage() 14 | .whenIGoToLoginPage() 15 | .andILoginToN11("onur@swtestacademy.com", "11223344") 16 | .thenIVerifyLogEntryFailMessage(); 17 | } 18 | 19 | @Test 20 | public void invalidLoginTest_EmptyUserEmptyPassword2() { 21 | page.getPage(HomePage.class) 22 | .givenIAmAtHomePage() 23 | .whenIGoToLoginPage() 24 | .andILoginToN11("", "") 25 | .thenIVerifyLoginUserNameErrorMessage("Lütfen e-posta adresinizi girin.") 26 | .thenIVerifyPasswordErrorMessage("Bu alanın doldurulması zorunludur."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/tests/LoginTest.java: -------------------------------------------------------------------------------- 1 | package tests; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.junit.jupiter.api.parallel.Execution; 5 | import org.junit.jupiter.api.parallel.ExecutionMode; 6 | import pages.HomePage; 7 | 8 | @Execution(ExecutionMode.CONCURRENT) 9 | public class LoginTest extends BaseTest { 10 | @Test 11 | public void invalidLoginTest_InvalidUserNameInvalidPassword() { 12 | page.getPage(HomePage.class) 13 | .givenIAmAtHomePage() 14 | .whenIGoToLoginPage() 15 | .andILoginToN11("onur@swtestacademy.com", "11223344") 16 | .thenIVerifyLogEntryFailMessage(); 17 | } 18 | 19 | @Test 20 | public void invalidLoginTest_EmptyUserEmptyPassword() { 21 | page.getPage(HomePage.class) 22 | .givenIAmAtHomePage() 23 | .whenIGoToLoginPage() 24 | .andILoginToN11("", "") 25 | .thenIVerifyLoginUserNameErrorMessage("Lütfen e-posta adresinizi girin.") 26 | .thenIVerifyPasswordErrorMessage("Bu alanın doldurulması zorunludur."); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/test/java/utils/ChromeOps.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import java.util.logging.Level; 4 | import org.openqa.selenium.chrome.ChromeOptions; 5 | import org.openqa.selenium.logging.LogType; 6 | import org.openqa.selenium.logging.LoggingPreferences; 7 | import org.openqa.selenium.remote.CapabilityType; 8 | import org.openqa.selenium.remote.DesiredCapabilities; 9 | 10 | public class ChromeOps { 11 | public static ChromeOptions getChromeOptions() { 12 | DesiredCapabilities caps = new DesiredCapabilities(); 13 | LoggingPreferences logPrefs = new LoggingPreferences(); 14 | logPrefs.enable(LogType.BROWSER, Level.ALL); 15 | caps.setCapability(CapabilityType.LOGGING_PREFS, logPrefs); 16 | ChromeOptions options = new ChromeOptions(); 17 | return options.merge(caps); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/test/java/utils/LogUtil.java: -------------------------------------------------------------------------------- 1 | package utils; 2 | 3 | import org.openqa.selenium.WebDriver; 4 | import org.openqa.selenium.logging.LogEntries; 5 | import org.openqa.selenium.logging.LogType; 6 | 7 | public class LogUtil { 8 | public static LogEntries getLogs(WebDriver driver) { 9 | return driver.manage().logs().get(LogType.BROWSER); 10 | } 11 | 12 | public static Boolean isLoginErrorLog(WebDriver driver) { 13 | LogEntries logEntries = driver.manage().logs().get(LogType.BROWSER); 14 | return logEntries.getAll().stream() 15 | .anyMatch(logEntry -> logEntry.getMessage().contains("An invalid email address was specified")); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/resources/junit-platform.properties: -------------------------------------------------------------------------------- 1 | junit.jupiter.execution.parallel.enabled=true 2 | junit.jupiter.execution.parallel.config.strategy=dynamic --------------------------------------------------------------------------------