logo logo

Installing Selenium WebDriver Using Python and Chrome

main post image

This tutorial will make web UI testing easy. We will build a simple yet robust web UI test solution using Python, pytest, and Selenium WebDriver. We will learn strategies for good test design as well as patterns for good automation code. By the end of the tutorial, you’ll be a web test automation champ! Your Python test project can be the foundation for your own test cases, too.

Tutorial Chapters

  1. Set Your Test Automation Goals (Chapter 1)
  2. Create A Python Test Automation Project Using Pytest (Chapter 2)
  3. You’re here → Installing Selenium WebDriver Using Python and Chrome (Chapter 3)
  4. Write Your First Web Test Using Selenium WebDriver, Python and Chrome (Chapter 4)
  5. Develop Page Object Selenium Tests Using Python (Chapter 5)
  6. How to Read Config Files in Python Selenium Tests (Chapter 6)
  7. Take Your Python Test Automation To The Next Level (Chapter 7)

With our new test project in place, let’s write some web UI tests with Selenium WebDriver!

What is WebDriver?

WebDriver is a programmable interface for interacting with live web browsers. It enables test automation to open a browser, send clicks, type keys, scrape text, and ultimately exit the browser cleanly. The WebDriver interface is a W3C Recommendation. The most popular implementation of the WebDriver standard is Selenium WebDriver, which is free and open source.

WebDriver has multiple components:

  1. Language Bindings. Packages like Selenium WebDriver provide programming language bindings for browser interactions. Selenium supports major languages like C#, Java, JavaScript, Ruby, and Python.
  2. Automation Code. Programmers use language bindings to automate browser interactions. Common interactions include finding elements, clicking them, and scraping text. Typically, this is written with a test automation framework.
  3. JSON Wire Protocol. Language bindings encode every interaction using JSON and send them as REST API requests to the browser’s driver. The JSON wire protocol is platform- and language- independent.
  4. Browser Driver. The driver is a standalone executable on the test machine. It acts as a proxy between the interaction’s caller and the browser itself. It receives JSON requests for interactions and sends them to the browser using HTTP.
  5. Browser. The browser renders the web pages under test. It is essentially controlled by the driver. All major browsers support WebDriver. Each browser also needs its own driver type installed on the same machine as the browser and accessible from the system path. For example, Google Chrome requires ChromeDriver.
Selenium WebDriver Architecture
Source: https://hackr.io/blog/complete-guide-selenium-webdriver

Installing Selenium WebDriver

For our test project, we will use Selenium WebDriver’s Python bindings with Google Chrome and ChromeDriver. We could use any browser, but let’s use Chrome because (a) it has a very high market share and (b) its Developer Tools will come in handy later.

Make sure that the most recent version of Chrome is installed on your machine (To check/update Chrome, go to the menu and select Help > About Google Chrome. Or, download and install it here.) Then, download the matching version of ChromeDriver here and add it to your system path.

Verify that ChromeDriver works from the command line:

$ chromedriver
Starting ChromeDriver 73.0.3683.68 (47787ec04b6e38e22703e856e101e840b65afe72) on port 9515
Only local connections are allowed.
Please protect ports used by ChromeDriver and related test frameworks to prevent access by malicious code.

Then, install Python’s selenium package into our environment:

$ pipenv install selenium --dev

Now, the machine should be ready for web testing!

New Tests

Create a new Python module under the tests/ directory named test_web.py. This new module will hold our web UI tests. Then, add the following import statements:

import pytest

from selenium.webdriver import Chrome
from selenium.webdriver.common.keys import Keys

Why do we need these imports?

  • pytest will be used for fixtures
  • Chrome provides ChromeDriver binding
  • Keys contains special keystrokes for browser interactions

WebDriver Setup and Cleanup

As a best practice, each test case should use its own WebDriver instance. Although the setup and cleanup adds a few seconds to each test, using one WebDriver instance per test keeps tests simple, safe, and independent. If one test hits a problem, then other tests won’t be affected. Plus, using a separate WebDriver instance for each test enables tests to be run in parallel.

WebDriver setup is best handled using a pytest fixture. Fixtures are pytest’s spiffy setup and cleanup functions that can also do dependency injection. Any test requiring a WebDriver instance can simply call the fixture to get it.

The Code

Add the following code to tests/test_web.py:

def browser():
  driver = Chrome()
  yield driver

browser is a pytest fixture function, as denoted by the @pytest.fixture decorator. Let’s step through each line to understand what this new fixture does.

The Lines

driver = Chrome()

Chrome() initializes the ChromeDriver instance on the local machine using default options. The driver object it returns is bound to the ChromeDriver instance. All WebDriver calls will be made through it.


The most painful part of web UI test automation is waiting for the page to load/change after firing an interaction. The page needs time to render new elements. If the automation attempts to access new elements before they exist, then WebDriver will raise a NoSuchElementException. Improper waiting is one major source of web UI test “flakiness.”

The implicitly_wait method above tells the driver to wait up to 10 seconds for elements to exist whenever attempting to find them. The waiting mechanism is smart: instead of sleeping for a hard 10 seconds, it will stop waiting as soon as the element appears. Implicit waits are declared once and then automatically used for all elements. Explicit waits, on the other hand, can provide custom waiting for each interaction at the cost of requiring explicit waiting calls. As a best practice, use one style of waiting exclusively for test automation. Mixing explicit and implicit waits can have nasty, unexpected side effects. For our test project, an implicit wait of 10 seconds should be reasonable (If your Internet connection is slow, please increase this timeout to compensate).

yield driver

A pytest fixture should return a value representing whatever was set up. Our fixture returns a reference to the initialized WebDriver. However, instead of using a return statement, it uses yield, meaning that the fixture is a generator. The first iteration of the fixture – in our case, the WebDriver initialization – is the “setup” phase to be called before a test begins. The second iteration – which will be the quit call – is the “cleanup” phase to be called after a test completes. Writing fixtures as generators keeps related setup and cleanup operations together as one concern.


Always quit the WebDriver instance at the end of a test, no matter what happens. Driver processes on the test machine won’t always die when test automation ends. Failing to explicitly quit a driver instance could leave it running as a zombie process, which could consume and even lock system resources.

Now that we have the WebDriver ready to go, we can write our first web UI test! Check it out here  😎 


TestProject Test Automation Tool


About the author


Andy Knight is the “Automation Panda” – an engineer, consultant, and international speaker who loves all things software. He specializes in building robust test automation systems from the ground up. Read his tech blog at AutomationPanda.com, and follow him on Twitter at @AutomationPanda.

Join TestProject Community

Get full access to the world's first cloud-based, open source friendly testing community. Enjoy TestProject's end-to-end test automation Platform, Forum, Blog and Docs - All for FREE.

Join Us Now  

Leave a Reply