Parallel Testing in Selenium WebDriver With Python Using Unittest
Parallel Testing in Selenium WebDriver With Python Using Unittest
Learn more about parallel testing with Python!
Join the DZone community and get the full member experience.Join For Free
Cross-browser testing is deemed to be an indispensable task for the modern-day release cycle. However, manual cross-browser testing could turn out to be very strenuous and time-consuming. This is a major hindrance that developers and testers face while performing browser compatibility testing for their website or web application across different operating systems, browsers, etc. This is where Selenium, a free and open source software, steps in!
Selenium is a popular automation testing framework for browser compatibility testing and is utilized for performing automated functional testing with less/minimal learning curve with respect to implementation.
Selenium and Python: Getting Started — Installation, Configuration, and More
Now that you have understood the advantages of using Selenium with Python for automation testing, we explain the basic steps for installation and configuration.
Note: In this blog, we use the Windows Environment, Python version 3.6, and Eclipse as Selenium IDE.
Let's get started:
- First, you need to install Python. Choose the appropriate version suitable for your Operating System, i.e. Windows, Linux, Mac, etc.
- Ensure that your PATH is appended with the location where Python executable is located. If Python is installed in the location C:\Users\\appdata\local\programs\python\Python36, you need to append the folder location to the environment variable PATH.
- Once you have installed Python, the next step is the installation of the Selenium package. It is also termed as ‘Python bindings for Selenium.’ These bindings are critical for performing Python automation testing.
- Now, you need to install the most important component in the testing framework — WebDriver. Selenium WebDriver is used for browser automation by pushing commands to the web browser. It is a collection of open-source APIs, and since it is platform-agnostic, source code written for the Windows platform would execute seamlessly on other Operating Systems, e.g. Linux, Mac, etc. This article will highlight how to perform parallel testing in Selenium WebDriver with Python.
Selenium requires the geckodriver in order to communicate with the Firefox browser. For performing parallel testing in Selenium, WebDriver and various browsers can be downloaded from the following locations:
In the code snippet below, we demonstrate code related to Python automation testing. After importing the Selenium WebDriver library [Lines 3-4], the developer can invoke a Firefox instance by using Option 1 [Line 8], given that the Firefox installation location is updated in the PATH environment variable and geckodriver.exe is executing in the background.
Option 2 [Line 11] can also be used in case you plan to manually invoke geckodriver.exe, which, in turn, starts a Firefox instance.
The usage of Selenium Web Server is optional, and it all depends on the manner in which you want to use the Selenium WebDriver. If you are planning to perform parallel testing in Selenium WebDriver with Python, or any other language through your local machine, where you have web browsers on which you intend to use for browser-compatibility testing, WebDriver API would suffice for your requirements. Selenium WebDriver would directly run the browser. Below are the ideal scenarios where you would require the Selenium Web Server:
- You are performing tests on a browser that is only available in a remote machine, not your local machine.
- You are using a complex, distributed Selenium Grid for cross-browser testing where the tests are distributed across different Virtual Machines (VMs).
- You are using HTMLUnit Driver and not Java Bindings, i.e. C#, Ruby, Python, etc.
The Selenium Web Server can be downloaded here.
Selenium WebDriver With Python – Usage and Examples
Now that you have the setup ready, you can now use Selenium WebDriver Python Bindings for the testing of your web application. Below is a simple piece of code that I used for Python automation testing; it will work with the ‘search functionality’ in Google.
# Import the necessary modules for development import time import unittest from selenium import webdriver from selenium.webdriver.common.keys import Keys # Invoke a new Firefox Instance ff_driver = webdriver.Firefox() # Blocking wait of 30 seconds in order to locate the element ff_driver.implicitly_wait(30) ff_driver.maximize_window() # Open the Home Page ff_driver.get("http://www.google.com") # Look for the Search Element and enter the Search Criteria search_criteria = ff_driver.find_element_by_id("lst-ib") search_criteria.clear() search_criteria.send_keys("Lambda Test") # Submit the Search results search_criteria.submit() # Sleep for 10 seconds in order to see the results time.sleep(10) # Close the Browser instance ff_driver.close()
You can save the file as search.py and compile using the following command:
Note: In case you are using an IDE like Eclipse, you can compile and execute your code using the PLAY button in the Eclipse IDE. Let’s do a code walkthrough and have a look at some of the critical parts in the above example for Selenium Webdriver for Python automation testing.
Import the selenium.webDriver module that provides the
Create a Firefox
Open the home page. In any case, the
WebDriver will wait until the page loads completely, after which the control returns back to the script. In this example, we have introduced a ‘Blocking Wait’ call of 30 seconds only for demonstration purpose.
The next step is to locate the necessary element on the Web Page. WebDriver offers a number of ways in which
find_element_by* can be used to find the required element on the page. In order to find the element name, you can make use of ‘Inspect Element’ functionality in the browser. You need to simply Right+Click on the page and select ‘Inspect Element’ option in order to find the necessary element. Below is the snapshot of finding details about ‘Input Box’ and ‘Google Search’ button on the Google Homepage.
Any pre-populated text in the input box is cleared using the
clear() method of the WebDriver, and the Key press is sent using the
Keys class imported from selenium.webdriver.common.keys. Once the input operation is complete, submit is invoked using the
submit() method in order to process the Search.
Finally, the browser session is closed using the
Now that you know how Selenium, Python, and WebDriver can be used; we proceed to the next section where we discuss how Selenium can be used for writing effective test cases. In order to write test cases using Selenium, the unittest module has to be imported. Though there are other options like py.test and nose, we will focus on
import unittest import time from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.options import Options class ChromeSearch(unittest.TestCase): def setUp(self): chrome_options = webdriver.ChromeOptions() self.driver = webdriver.Chrome(r"C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe", options=chrome_options) self.driver.maximize_window() # As per unittest module, individual test should start with test_ def test_search_lambdatest_chrome(self): driver_chrome = self.driver driver_chrome.get('http://www.google.com') time.sleep(10) search_criteria = driver_chrome.find_element_by_id("lst-ib") search_criteria.clear() search_criteria.send_keys("Lambda Test") # Check if the search returns any result assert "No results found." not in driver_chrome.page_source search_criteria.submit() time.sleep(10) def tearDown(self): # Close the browser. self.driver.close() class FirefoxSearch(unittest.TestCase): def setUp(self): self.driver = webdriver.Firefox() self.driver.maximize_window() # As per unittest module, individual test should start with test_ def test_search_lambdatest_firefox(self): driver_firefox = self.driver driver_firefox.get('http://www.google.com') time.sleep(10) search_criteria = driver_firefox.find_element_by_id("lst-ib") search_criteria.clear() search_criteria.send_keys("Lambda Test") # Check if the search returns any result assert "No results found." not in driver_firefox.page_source search_criteria.submit() time.sleep(10) # Anything declared in tearDown will be executed for all test cases def tearDown(self): # Close the browser. self.driver.close() if __name__ == "__main__": unittest.main()
The above test code can be executed from the shell using the command
python file-name.py. Let’s do a code walkthrough and focus on the important parts of the code.
Before getting into the actual implementation, important modules are imported.
unittest is a built-in Python module that is based on JUnit. It is used for organization of the test cases — more information about unittest can be found here. Similar to the previous example, the selenium.webdriver module, which supports the WebDriver implementation, is imported.
import unittest import time from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.options import Options
Now, we start with the actual
ChromeSearch is the name of the
testcase. The test case class is inherited from
setup() method is a part of the initialization and defines instructions that are executed before the
testcase. In the snippet below, we create an instance of Chrome WebDriver for performing Selenium WebdDriver with Python for automation testing.
def setUp(self): chrome_options = webdriver.ChromeOptions() self.driver = webdriver.Chrome(r"C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe", options=chrome_options) self.driver.maximize_window()
Once the initialization is done, we proceed with the
testcase method. As per the unittest module, individual test should always start with
test_. In the snippet below, the
testcase method is
driver_chrome is the local reference to the driver object that was created in the
setUp() method. Henceforth, the local reference (in this case,
driver_chrome) will be used for further implementation. For details about the WebDriver implementation, please refer to Example 1 where we have already provided an in-depth explanation.
def test_search_lambdatest_chrome(self): driver_chrome = self.driver
tearDown() method is called immediately after the test method completes execution, since this is the place where cleanup is performed. In the code snippet below, close operation is performed on the browser, i.e. Chrome.
def tearDown(self): # Close the browser. self.driver.close()
The implementation in the
FirefoxSearch testcase method [Line-34] is similar to
ChromeSearch testcase method [Line-7], except that in that method
Firefox WebDriver instance is created.
The final lines of code are the boilerplate code to run the test suite;
unittest.main() provides a command-line interface to execute the test script, though there are many other options to execute the tests with a finer level of control.
if __name__ == "__main__": unittest.main()
The examples that we have showcased above have a Firefox and Chrome browser at the center of the entire testing process. What if your requirement is to test your web app with just the Firefox browser (version 64.0) installed on a Windows 10 machine? In such a process, you would need the required setup with the same version of Firefox installed on it. This approach is not only expensive but it is also non-scalable.
Performing parallel testing in Selenium WebDriver with Python for automation testing could save you a lot of time by speeding up your slow automated UI tests. If there are less number of tests, you might not require parallel testing in Selenium WebDriver for Python or any other language, but once the complexity of the project increases (or the number of tests to be executed increase), parallel testing is the ideal mechanism to achieve the best results in the minimum possible time. Nowadays, more teams are focused on making use of Continuous Integration (CI) and Continuous Delivery (CD) in the overall software development and testing process. Getting the best out of ‘parallel testing’ is important for the implementation of Continuous Integration (CI).
Published at DZone with permission of Himanshu Seth . See the original article here.
Opinions expressed by DZone contributors are their own.