Web Testing With PyWebRunner

by Scott Blevins

Posted on 07/18/2016 04:26 PM

So you want to test your application using Selenium and Python? You've come to the right place.

What is PyWebRunner?

PyWebRunner is a wrapper library for using Selenium inside of Python. Though Python 3+ is obviously preferred, PyWebRunner runs comfortably on Python 2.7.

Origins of PyWebRunner

I wrote PyWebRunner to solve a problem we had at BriteCore. We needed to be able to test our extensive legacy Javascript code while being able to simultaneously test our other pages that were written in the newer stack.

Originally, we were using a modified version of Casper JS + Phantom to do our testing but we were plagued with the following problems:

  • Random test failures
  • CasperJS couldn't be upgraded easily because upstream had changed significantly.
  • Limited to headless testing only.
  • Phantom JS wasn't a good representation of our customer's browsers.
  • Tests took a long time to write.
  • Test code was complex and highly nested with callbacks.
  • Nobody liked writing tests for our frontend.
  • Test coverage was poor.

The Solution

I started writing a Selenium-based test runner inside of the BriteCore codebase. I called it "WebRunner" and I set out to fix all the issues that I outlined above.

Without a doubt, the most important problem to fix was the non-deterministic nature of our current tests. Jenkins would scream at us for failed builds and we learned to ignore certain front-end tests because we knew the likelihood was that it was yet another meaningless failure. The signal to noise ratio made it such that we didn't know what was a legitimate failure.

That's an unacceptable condition for a company that ships daily updates to an enterprise-grade policy management system.

Fortunately, Selenium provides a lot of the built-in functionality that I needed. I primarily needed to be able to wait for elements to be visible, clickable, and invisible. Unfortunately the code I was writing was pretty ugly and didn't seem to fit with my requirements of tests being quick and easy to write.

To compare:

from selenium.webdriver.support import expected_conditions as EC

element = WebDriverWait(driver, 10).until(
    EC.presence_of_element_located((By.CSS, "#some-id-here"))



I wanted test scripts to be flat and the pieces to be simple actions that were easy and intuitive to write. I knew that by making the tests easy to write, it would improve adoption-rate by the engineers as well as help keep the tests stable.

Blog Search