{"id":14978795,"url":"https://github.com/eliasnogueira/selenium-java-lean-test-architecture","last_synced_at":"2025-05-15T09:09:01.185Z","repository":{"id":38123998,"uuid":"139874676","full_name":"eliasnogueira/selenium-java-lean-test-architecture","owner":"eliasnogueira","description":"Ready to use Lean Test Automation Architecture using Java and Selenium WebDriver to speed up your test automation","archived":false,"fork":false,"pushed_at":"2025-05-13T17:12:07.000Z","size":35432,"stargazers_count":558,"open_issues_count":0,"forks_count":181,"subscribers_count":34,"default_branch":"main","last_synced_at":"2025-05-15T09:08:53.542Z","etag":null,"topics":["automated-testing","java","parallel","selenium-webdriver","testng"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/eliasnogueira.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-07-05T16:24:15.000Z","updated_at":"2025-05-13T17:11:39.000Z","dependencies_parsed_at":"2024-03-28T21:49:32.821Z","dependency_job_id":"e4bc3654-3c4b-42c9-9f20-a572fa7bd494","html_url":"https://github.com/eliasnogueira/selenium-java-lean-test-architecture","commit_stats":{"total_commits":388,"total_committers":7,"mean_commits":55.42857142857143,"dds":"0.10824742268041232","last_synced_commit":"b0efbf8cf7d788dac71508cf02375491dd43df6e"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliasnogueira%2Fselenium-java-lean-test-architecture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliasnogueira%2Fselenium-java-lean-test-architecture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliasnogueira%2Fselenium-java-lean-test-architecture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/eliasnogueira%2Fselenium-java-lean-test-architecture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/eliasnogueira","download_url":"https://codeload.github.com/eliasnogueira/selenium-java-lean-test-architecture/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254310520,"owners_count":22049470,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["automated-testing","java","parallel","selenium-webdriver","testng"],"created_at":"2024-09-24T13:58:25.229Z","updated_at":"2025-05-15T09:08:56.175Z","avatar_url":"https://github.com/eliasnogueira.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lean Test Automation Architecture using Java and Selenium WebDriver\n\n[![Actions Status](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/workflows/Build%20and%20Test/badge.svg)](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/actions)\n\n**This project delivers to you a complete lean test architecture for your web tests using the best frameworks and\npractices.**\n\nIt has a complete solution to run tests in different ways:\n\n* local testing using the browser on your local machine\n* parallel (or single) testing using Selenium Docker\n* local testing using TestContainers\n* Distributed execution using Selenium Grid\n\n## Examples\n\n### Local testing execution example\n\n![Local testing execution example](assets/example_filed_test_with_report.gif)\n\n### Parallel testing execution example with Selenium Grid\n\n![Parallel testing execution example with Selenium Grid](assets/selenium-grid-execution.gif)\n\n## Languages and Frameworks\n\nThis project uses the following languages and frameworks:\n\n* [Java 23](https://openjdk.java.net/projects/jdk/23/) as the programming language\n* [TestNG](https://testng.org/doc/) as the UnitTest framework to support the test creation\n* [Selenium WebDriver](https://www.selenium.dev/) as the web browser automation framework using the Java binding\n* [AssertJ](https://joel-costigliola.github.io/assertj/) as the fluent assertion library\n* [Allure Report](https://docs.qameta.io/allure/) as the testing report strategy\n* [DataFaker](https://www.datafaker.net/) as the faker data generation strategy\n* [Log4J2](https://logging.apache.org/log4j/2.x/) as the logging management strategy\n* [Owner](http://owner.aeonbits.org/) to minimize the code to handle the properties file\n* [TestContainers](https://java.testcontainers.org/modules/webdriver_containers/) Webdriver Containers\n\n## Test architecture\n\nWe know that any automation project starts with a good test architecture.\n\nThis project can be your initial test architecture for a faster start.\nYou will see the following items in this architecture:\n\n* [Page Objects pattern](#page-objects-pattern)\n* [Execution types](#execution-types)\n* [BaseTest](#basetest)\n* [TestListener](#testlistener)\n* [Logging](#logging)\n* [Configuration files](#configuration-files)\n* [Parallel execution](#parallel-execution)\n* [Test Data Factory](#test-data-factory)\n* [Profiles executors on pom.xml](#profiles-executors-on-pomxml)\n* [Pipeline as a code](#pipeline-as-a-code)\n* [Test environment abstraction](#execution-with-docker-selenium-distributed)\n\nDo you have any other items to add to this test architecture? Please do a pull request or open an issue to discuss.\n\n### Page Objects pattern\n\nI will not explain the Page Object pattern because you can find a lot of good explanations and examples on the internet.\nInstead, I will explain what exactly about page objects I'm using in this project.\n\n#### AbstractPageObject\n\nThis class has a protected constructor to remove the necessity to init the elements using the Page Factory.\nAlso, it sets the timeout from the `timeout` property value located on `general.properties` file.\n\nAll the Page Object classes should extend the `AbstractPageObject`.\nIt also tries to remove the `driver` object from the Page Object class as much as possible.\n\n\u003e **Important information**\n\u003e\n\u003e There's a `NavigationPage` on the `common` package inside the Page Objects.\n\u003e Notice that all the pages extend this one instead of the `AbstractPageObject`. I implemented this way:\n\u003e * because the previous and next buttons are fixed on the page (there's no refresh on the page)\n\u003e * to avoid creating or passing the new reference to the `NavigationPage` when we need to hit previous or next buttons\n\nAs much as possible avoid this strategy to not get an `ElementNotFoundException` or `StaleElementReferenceException`.\nUse this approach if you know that the page does not refresh.\n\n### Execution types\n\nThere are different execution types:\n\n- `local`\n- `local-suite`\n- `selenium-grid`\n- `testcontainers`\n\nThe `TargetFactory` class will resolve the target execution based on the `target` property value located\non `general.properties` file. Its usage is placed on the `BaseWeb` class before each test execution.\n\n#### Local execution\n\n##### Local machine\n\n**This approach is automatically used when you run the test class in your IDE.**\n\nWhen the `target` is `local` the `createLocalDriver()` method is used from the `BrowserFactory` class to return the\nbrowser instance.\n\nThe browser used in the test is placed on the `browser` property in the `general.properties` file.\n\n##### Local Suite\n\nIt's the same as the Local Execution, where the difference is that the browser is taken from the TestNG suite file\ninstead of the `general.properties`\nfile, enabling you to run multi-browser test approach locally.\n\n##### Testcontainers\n\nThis execution type uses the [WebDriver Containers](https://www.testcontainers.org/modules/webdriver_containers/) in\nTestcontainers to run the tests in your machine, but using the Selenium docker images for Chrome or Firefox.\n\nWhen the `target` is `testcontainers` the `TargetFactory` uses the `createTestContainersInstance()` method to initialize\nthe container based on the browser set in the `browser` property. Currently, Testcontainers only supports Chrome and\nFirefox.\n\nExample\n\n```shell\nmvn test -Pweb-execution -Dtarget=testcontainers -Dbrowser=chrome\n```\n\n#### Remote execution\n\n##### Selenium Grid\n\nThe Selenium Grid approach executes the tests in remote machines (local or remote/cloud grid).\nWhen the `target` is `selenium-grid` the `getOptions` method is used from the `BrowserFactory` to return the browser\noption\nclass as the remote execution needs the browser capability.\n\nThe `DriverFactory` class has an internal method `createRemoteInstance` to return a `RemoteWebDriver` instance based on\nthe browser capability.\n\nYou must pay attention to the two required information regarding the remote execution: the `grid.url` and `grid.port`\nproperty values on the `grid.properties` file. You must update these values before the start.\n\nIf you are using the `docker-compose.yml` file to start the Docker Selenium grid, the values on the `grid.properties`\nfile should work.\n\nYou can take a look at the [Execution with Docker Selenium Distributed](#execution-with-docker-selenium-distributed)\nto run the parallel tests using this example.\n\n#### BrowserFactory class\n\nThis Factory class is a Java enum that has all implemented browsers to use during the test execution.\nEach browser is an `enum`, and each enum implements four methods:\n\n* `createLocalDriver()`: creates the browser instance for the local execution. The browser driver is automatically\n  managed by the WebDriverManager library\n* `createDriver()`: creates the browser instance for the remote execution\n* `getOptions()`: creates a new browser `Options` setting some specific configurations, and it's used for the remote\n  executions using the Selenium Grid\n* `createTestContainerDriver()` : Creates selenium grid lightweight test container in Standalone mode with\n  Chrome/Firefox/Edge browser support.\n\nYou can see that the `createLocalDriver()` method use the `getOptions()` to get specific browser configurations, as\nstarting the browser maximized and others.\n\nThe `getOptions()` is also used for the remote execution as it is a subclass of the `AbstractDriverOptions` and can be\nautomatically accepted as either a `Capabilities` or `MutableCapabilities` class, which is required by\nthe `RemoteWebDriver` class.\n\n#### DriverManager class\n\nThe\nclass [DriverManager](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/driver/DriverManager.java)\ncreate a `ThreadLocal` for the WebDriver instance, to make sure there's no conflict when we run it in parallel.\n\n### BaseTest\n\nThis testing pattern was implemented on\nthe [BaseWeb](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/test/java/com/eliasnogueira/BaseWeb.java)\nclass to automatically run the pre (setup) and post (teardown) conditions.\n\nThe pre-condition uses `@BeforeMethod` from TestNG creates the browser instance based on the values passed either local\nor remote execution.\nThe post-condition uses `@AfterMethod` to close the browser instance.\nBoth have the `alwaysRun` parameter as `true` to force the run on a pipeline.\n\nPay attention that it was designed to open a browser instance to each `@Test` located in the test class.\n\nThis class also has the `TestListener` annotation which is a custom TestNG listener, and will be described in the next\nsection.\n\n### TestListener\n\nThe `TestListener` is a class that\nimplements [ITestListener](https://testng.org/doc/documentation-main.html#logging-listeners).\nThe following method is used to help logging errors and attach additional information to the test report:\n\n* `onTestStart`: add the browser information to the test report\n* `onTestFailure`: log the exceptions and add a screenshot to the test report\n* `onTestSkipped`: add the skipped test to the log\n\n### Logging\n\nAll the log is done by the Log4J using the `@Log4j2` annotation.\n\nThe `log4j2.properties` has two strategies: console and file.\nA file with all the log information will be automatically created on the user folder with `test_automation.log`\nfilename.\nIf you want to change it, update the `appender.file.fileName` property value.\n\nThe `log.error` is used to log all the exceptions this architecture might throw. Use `log.info` or `log.debug` to log\nimportant information, like the users, automatically generated by the\nfactory [BookingDataFactory](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/data/BookingDataFactory.java)\n\n### Parallel execution\n\nThe parallel test execution is based on\nthe [parallel tests](https://testng.org/doc/documentation-main.html#parallel-tests)\nfeature on TestNG. This is used by `selenium-grid.xml` test suite file which has the `parallel=\"tests\"` attribute and\nvalue,\nwhereas `test` item inside the test suite will execute in parallel.\nThe browser in use for each `test` should be defined by a parameter, like:\n\n```xml\n\n\u003cparameter name=\"browser\" value=\"chrome\"/\u003e\n```\n\nYou can define any parallel strategy.\n\nIt can be an excellent combination together with the grid strategy.\n\n#### Execution with Docker Selenium Distributed\n\nThis project has the `docker-compose.yml` file to run the tests in a parallel way using Docker Selenium.\nTo be able to run it in parallel the file has\nthe [Dynamic Grid Implementation](https://github.com/SeleniumHQ/docker-selenium#dynamic-grid-) that will start the\ncontainer on demand.\n\nThis means that Docker Selenium will start a container test for a targeting browser.\n\nPlease note that you need to do the following actions before running it in parallel:\n\n* Docker installed\n* Pull the images for Chrome Edge and Firefox - Optional\n    * Images are pulled if not available and initial test execution will be slow\n        * `docker pull selenium-standalog-chrome`\n        * `docker pull selenium-standalog-firefox`\n        * `docker pull selenium/standalone-edge`\n    * If you are using a MacBook with either M1 or M2 chip you must check the following experimental feature in Docker\n      Desktop: Settings -\u003e Features in development -\u003e Use Rosetta for x86/amd64 emulation on Apple Silicon\n* Pay attention to the `grid/config.toml` file that has comments for each specific SO\n* Start the Grid by running the following command inside the `grid` folder\n    * `docker-compose up`\n* Run the project using the following command\n\n```shell\nmvn test -Pweb-execution -Dsuite=selenium-grid -Dtarget=selenium-grid -Dheadless=true\n```\n\n* Open the [Selenium Grid] page to see the node status\n\n### Configuration files\n\nThis project uses a library called [Owner](http://owner.aeonbits.org/). You can find the class related to the property\nfile reader in the following classes:\n\n* [Configuration](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/config/Configuration.java)\n* [ConfigurationManager](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/config/ConfigurationManager.java)\n\nThere are 3 properties (configuration) files located on `src/test/java/resources/`:\n\n* `general.properties`: general configuration as the target execution, browser, base url, timeout, and faker locale\n* `grid.properties`: url and port for the Selenium grid usage\n\nThe properties were divided into three different ones to better separate the responsibilities and enable the changes\neasy without having a lot of properties inside a single file.\n\n### Test Data Factory\n\nIs the utilization of the Factory design pattern with the Fluent Builder to generate dynamic data.\nThe [BookingDataFactory](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/data/BookingDataFactory.java)\nhas only one factory `createBookingData` returning a `Booking` object with dynamic data.\n\nThis dynamic data is generated by JavaFaker filling all the fields using the Build pattern.\nThe [Booking](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/model/Booking.java)\nis the plain Java objects\nand\nthe [BookingBuilder](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/model/BookingBuilder.java)\nis the builder class.\n\nYou can see the usage of the Builder pattern in\nthe [BookingDataFactory](https://github.com/eliasnogueira/selenium-java-lean-test-achitecture/blob/master/src/main/java/com/eliasnogueira/data/BookingDataFactory.java)\nclass.\n\nReading reference: https://reflectoring.io/objectmother-fluent-builder\n\n### Profiles executors on pom.xml\n\nThere is a profile called `web-execution` created to execute the test suite `local.xml`\ninside `src/test/resources/suites` folder.\nTo execute this suite, via the command line you can call the parameter `-P` and the profile id.\n\nEg: executing the multi_browser suite\n\n``` bash\nmvn test -Pweb-execution \n```\n\nIf you have more than one suite on _src/test/resources/suites_ folder you can parameterize the xml file name.\nTo do this you need:\n\n* Create a property on `pom.xml` called _suite_\n\n```xml\n\n\u003cproperties\u003e\n    \u003csuite\u003elocal\u003c/suite\u003e\n\u003c/properties\u003e\n```\n\n* Change the profile id\n\n```xml\n\n\u003cprofile\u003e\n    \u003cid\u003eweb-execution\u003c/id\u003e\n\u003c/profile\u003e   \n```\n\n* Replace the xml file name to `${suite}` on the profile\n\n```xml\n\n\u003cconfiguration\u003e\n    \u003csuiteXmlFiles\u003e\n        \u003csuiteXmlFile\u003esrc/test/resources/suites/${suite}.xml\u003c/suiteXmlFile\u003e\n    \u003c/suiteXmlFiles\u003e\n\u003c/configuration\u003e\n```\n\n* Use `-Dsuite=suite_name` to call the suite\n\n````bash\nmvn test -Pweb-execution -Dsuite=suite_name\n````\n\n### Pipeline as a code\n\nThe two files of the pipeline as a code are inside `pipeline_as_code` folder.\n\n* GitHub Actions to use it inside the GitHub located at `.github\\workflows`\n* Jenkins: `Jenkinsfile` to be used on a Jenkins pipeline located at `pipeline_as_code`\n* GitLab CI: `.gitlab-ci.yml` to be used on a GitLab CI `pipeline_as_code`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feliasnogueira%2Fselenium-java-lean-test-architecture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feliasnogueira%2Fselenium-java-lean-test-architecture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feliasnogueira%2Fselenium-java-lean-test-architecture/lists"}