We’ve already talked about automating tests, now it’s time to take a look at seven of the best Python test automation tools.
The good news is that the Python standard library already includes excellent unit testing tools. You can go a long way toward setting up robust test automation using the language’s built-in capabilities. But adding test automation to a Python codebase is straightforward since the language is used for a variety of different tasks, including building the test automation tools themselves.
Expand Your Test Coverage
You can set up the degree and level of Python test automation you need, and evolve your tests along with your codebase. In this post, we’ll look into 7 python test automation options. But before that, let’s understand how Python fits in test automation.
Python Test Automation: Can Python Be Used for Test Automation?
A short answer is “Yes”. Test automation is the practice of automating the execution of tests using programs or tools to run tests faster and minimize human dependency in the testing process. When testing a product, you might have to run different tests repeatedly. Test automation helps you make this process faster and by defining tests in code, you can reuse the same script again and again. Python test automation is simply using Python for test automation.
Python is one of testing teams’ favorite programming languages. It has multiple features that make it suitable for automated testing. For example, you can benefit from Python’s dynamic typing but also make use of checkers like Pyre for static typing. Python is easy to learn and can also be used for complex problems. Therefore, users of different skill levels can use Python.
Python is well-known for having a library available for almost everything so you don’t need to waste time writing code from scratch. And if you find something that’s not exactly what you wanted, you can also make changes to the libraries and use them as per your use case. And in addition to all this, Python has an amazing community to help you when you’re stuck.
Now that we’ve understood how Python can be useful in test automation, let’s look into some tools.
Python Test Automation Tools
PyUnit and Nose2
PyUnit is the Python unit testing framework. It joined the Python standard library back in version 2.1 and is compatible with all subsequent versions of the language. PyUnit is a Python implementation of JUnit, the standard unit testing framework for Java. So developers switching from Java to Python will find it very easy to use. Both testing frameworks owe their existence to Kent Beck’s Smalltalk testing framework.
PyUnit gives you all the essential tools you need to create automated tests.
- Fixtures so you can set up and tear down the objects required in a test.
- Methods for you to perform the actual tests.
- Suites for you to group test classes into logical units.
- Runners for executing tests.
Here’s an example of a basic unit test:
import unittest class SimpleWidgetTestCase(unittest.TestCase): def setUp(self): self.widget = Widget("The widget") class DefaultWidgetSizeTestCase(SimpleWidgetTestCase): def runTest(self): assert self.widget.size() == (50,50), 'incorrect default size'
SimpleWidgetTestCase uses the setUp test fixture to create the Widget under test. DefaultWidgetSizeTestCase subclasses this class and tests the Widget’s size.
PyUnit is an excellent place to begin setting up Python test automation, but it’s only a basic set of tools. You still need tools to automate running the tests and collecting the results. This is where Nose comes in.
Nose2 takes PyUnit a step further by adding support for automatic test discovery and plugins for test execution and collecting documentation. Nose2’s plugin system adds useful features like decorators, parameterized testing, and test discovery. For example, the AllModules plugin discovers all tests and gathers the output from them.
Nose2 also offers Such, a DSL for writing functional tests.
If you place the sample code in a file named test_widgets.py Nose2’s test runner will find the test and run it for you. All you need to do is prefix your files with tests_.
PyTest
PyTest is a native Python test library with a superset of PyUnit’s features. Rather than modeling JUnit’s architecture, it has a distinctly Python flavor. It makes heavy use of Python decorators and assertions.
PyTest also supports parameterized testing (without the aid of plugins like Nose) that improves code reuse and simplifies code coverage.
If you write the same test we used above with Pytest, it looks more declarative.
@pytest.fixture def widget(): return Widget("The widget") def test_widget_size(widget): assert widget.size() == (50,50), 'incorrect default size'
PyTest uses the test fixture to pass a Widget to the test method.
In addition to fixtures, suites, and test runners, PyTest has its own support for test discovery. You can select sets of tests to run based on their method names, packages, or decorators you add to your test code. PyTest can also run tests in parallel. Used together, these features make it easier to manage large code bases than with PyUnit.
PyTest includes reporting in plain text, XML or HTML. You can also add code coverage to PyTest reports.
Even though you can use PyTest on its own, you can integrate it with other test frameworks and test runners, like PyUnit and Nose2. Because of this compatibility, PyTest is an excellent choice for a codebase that needs better test coverage or is getting ready to grow. Pytest requires Python 3.7 or later, or PyPy3.
Behave
PyUnit and PyTest are potent traditional unit test frameworks, but what if you want to write behavior-driven tests?
Behave is a behavior-driven (BDD) test framework. It differs from PyUnit and PyTest in a critical way: you write your tests in Cucumber’s Gherkin language instead of Python code. Even though it’s not an official Cucumber variant, it has complete support for Gherkin and it one of the most popular BDD frameworks for Python.
Behave is so widely used that Jetbrains offers a plugin in PyCharm Professional Edition for it. There’s also a wealth of online tutorials and documentation for working with Behave.
You write your tests in a natural language grammar that describes a feature in terms of behavior and expected test outcomes. Then, you write your tests with annotations that correspond to the behavior and conditions. Behave runs the test, collects the results, and documents them in terms of your behavior files.
If you’re interested in or already using behavior-driven development (BDD), Behave is one of your best options for Python development. It comes with integrations for both Django and Flask so that you can use it in your full-stack projects, too.
You could implement the previous test with Behave like this.
Here’s the natural language grammar.
Feature: widget size Scenario: verify a widget's size Given we have a widget When the widget is valid Then the size is correct
Here’s the Python code. Given, When, and Then each has an associated annotation.
from behave import * @given('we have a widget') def step_given_a_widget(context): context.widget = Widget('The widget') @when('the widget is valid') def step_widget_is_valid(context) assert context.widget is not None @then('the size is correct') def step_impl(context): assert context.widget.size() == (50,50)
Behave tests are more complicated than tests with PyUnit or Pytest, since you need to write natural descriptions of the behavior and the tests. You can find an extensively documented example here, though.
Lettuce
Lettuce is a behavior-driven automation tool for Selenium and Python. Similar to Behave, it uses a text syntax based on Gherkin to describe test scenarios, but it’s not quite as compatible as Behave. Lettuce has a smaller footprint than Behave though and works well with small projects.
It’s also easy to integrate with other frameworks, like Selenium and Nose.
Lettuce tests resemble Behave. Here is the natural language grammar.
Feature: widget size Scenario: verify a widget's size Given we have a widget When the widget is valid Then the size is correct
Here’s the code. Instead of separate annotations for each step of the test, Lettuce uses the step annotation.
from lettuce import step from lettuce import world @step('we have a widget') def step_given_a_widget(step): world.widget = Widget('The widget') @step('the widget is valid') def step_widget_is_valid(step) assert world.widget is not None @step('the size is corrrect') def step_impl(context): assert world.widget.size() == (50,50)
When you integrate Lettuce with Selenium’s Python bindings, you have a robust framework for testing Django applications. So, if you’re not comfortable with Jasmine’s JavaScript syntax, Lettuce may be a better option.
However, Lettuce has not been updated since 2016. You can still download it and integrate it with your code, but it is no longer supported.
Jasmine for Python Test Automation
BDD isn’t just a popular development paradigm for Python; it’s gained a lot of ground with web development, too. Jasmine is a popular test framework for using BDD with web applications. You probably think of Jasmine as a tool for testing JavaScript applications, but you can use it for Python test automation tool, too.
Thanks to Jasmine-Py, you can integrate Jasmine into your Django projects. This gives you the ability to run Jasmine from your Python environment and from inside your CI/CD server.
Testing web applications based on behavior, rather than a DOM, makes your tests more resilient to change. This is a tremendous advantage when you’re evaluating how your Django code builds pages. Rather than using Gherkin, you’ll write your tests in Jasmine’s test grammar.
But, you can apply the results to both your web and your Django code.
Robot Framework
Robot Framework is an open-source test automation framework. Organizations use it for automated acceptance testing. You write your tests in Robot’s DSL, a test data syntax that the framework uses to generate acceptance tests.
Rather than being behavior-focused like Jasmine, Robot is keyword-driven.
A keyword is any function or method that you can call in a test. Keywords are defined in Robot, either in the core system or in user-defined test libraries. You can also define keywords in terms of existing keywords.
You extend Robot’s capabilities with test libraries written in either Python or Java. So, in addition to using it to test your Python code, you can extend Robot with Python, too. You also have access to an extensive library of Robot plugins.
Robot’s DSL makes it easy to create scenarios for Python test automation. With the right set of plug-ins, you can automate almost any aspect of your acceptance testing. You can also create new higher-level keywords using the existing keywords in Robot.
Selenium Framework
Selenium is one of the most popular testing frameworks that also comes with a Selenium Python package so you can integrate it within your Python testing projects. It helps you test your application across browsers and platforms. It uses a web driver to control browsers and run tests and it has various functions to simulate users’ behavior. Selenium is easy to learn and implement so it makes things easy for the automated testing team.
The following example code snippet logs in to a web application and takes a screenshot:
driver = webdriver.Chrome("chromedriver") driver.get("https://example.com")
driver.find_element_by_id("email").send_keys('[email protected]')
driver.find_element_by_id("password").send_keys('this is a password')
driver.find_element_by_name("login").click() driver.save_screenshot('post_login.png')
You Need Python Test Automation
Python has steadily risen in popularity in the past decade. You can see its rise in the TIOBE index here. There’s a good chance you’re already using Python or considering adding it to your toolbox soon.
Python’s increased adoption has led to a proliferation in frameworks, testing tools, and other utilities. Whether you’re building a backend REST service, a full-stack web service, or any other type of application, there’s a Python test automation framework for you.
Which one best suits your needs? Testim has a guide to help you make an informed decision. Take a look at it today and get started with your Python testing.
This post was written by Eric Goebelbecker. Eric has worked in the financial markets in New York City for 25 years, developing infrastructure for market data and financial information exchange (FIX) protocol networks. He loves to talk about what makes teams effective (or not so effective!)