Build A Selenium Python Test Suite From Scratch Using Unittest

In this latest Selenium Python tutorial, we’ll cover some of the key topics so that it is easy for you to learn and automate the Web applications using Selenium Webdriver APIs in Python.

Before starting with test automation, we should first prepare a set of test cases for the features that are active in the Web application. These can be cases meant for acceptance criteria or part of the functional testing landscape.

Then, for automation, we’ll need an automation framework that could facilitate test management capabilities like creating data driven tests, setting up test preconditions and postconditions, check the expected and actual output. And most importantly, it should provide report generation capability.

Since not all these features are available in Selenium WebDriver, so we’ll utilize the Python’s unit testing framework and use its features along with Selenium Webdriver.

Along with this post, we would recommend you to read the below tutorial as well. It’ll help you setup Selenium with Python and configure browsers like Firefox, Chrome, and IE.

Let’s now look at the list of topics that we’re going to cover in this Selenium Python tutorial.

1. Understanding Python Unittest Framework and Its Features.
1.1. Five Components of Python Unittest Framework.
1.2. Prepare a Test Case Class to Automate a Scenario.
1.3. Using setUp() Method to Manage Test Pre-requisites.
2. Start Writing Selenium-Python Test Scripts Using Unittest.
2.1. Create Your First Selenium Test in Python with Unittest.
2.2. Define Cleanup Strategy to Free Resources Post Test Execution.
2.3. How to Execute the Test Case from Commandline?
2.4. Add One More Selenium-Python Test Case.
2.5. Refactoring setUp() and tearDown() Methods for Optimization.
3. Assertions in Python Unittest Framework.
3.1. List of Assert Methods in Python Unittest Module.

4. Create Selenium-Python Test Suite Using Unittest.
4.1. Group Test Cases into a Test Suite.
4.2. Execute the Test Suite.
5. Generate HTML Test Suite Execution Report.

Build A Selenium Python Test Suite From Scratch Using Unittest.

1. Understanding Python Unittest Framework and Its Features.

Python Unittest library inherits its root from a third-party module known as PyUnit. It was Steve Purcell who ideated PyUnit based on the famous JUnit framework. And later it grew as an official Python module beginning from the version 2.5.

Like the JUnit, Python Unittest module splits up its functionality among five key components. All the five elements work in tandem to support automation testing. Let’s discuss each of them one by one in detail.

1.1. Five Components of Python Unittest Framework.

Selenium Python Unittest Framework

Selenium Python Unittest Framework

Test Loader – It’s a Python class which loads test cases and suites created locally or from an external data source like a file. It releases a TestSuite object that carries those cases and suites.

Test Case – The TestCase class holds the test handlers and provides hooks for preparing each handler and for cleaning up after execution.

Test Suite – It acts as a container for grouping test cases. With the help of a test suite, you can combine a set of test cases representing specific functionalities of the application under test.

Test Runner – It provides a runnable interface for the execution of tests and delivers the results to the user. It can use channels like a GUI, a textual medium, or return a standard code to notify the results of test execution.

Test Report – This component organizes test results, display pass/fail status of the executed test cases. It even provides the details of steps, summary of overall run and the time lapsed in execution.

1.2. Prepare a Test Case Class to Automate a Scenario.

We can create one or more tests by inheriting the TestCase class available in the Unittest module. To add a case, we also need to provide a corresponding test method (a handler) to the derived class. To finalize a test case, we can use assert or any of its variations for reporting test status.

Here are some of the most common assert functions used almost in all tests.

a. Use assertEqual() to check for an expected result.
b. Use assertTrue() to verify a condition.
c. Use assertRaises() to verify that an expected exception gets raised.

In addition to the test handler, we can also add routines like setUp() and tearDown() to manage creation and disposition of any objects or conditions that are mandatory for a test.

Let’s now start using the Unit test library and write a simple test by inheriting the TestCase class. For this, you’ll need to import the <unittest> module and define a class that inherits the TestCase class.

Look at the code below to get a feel of the test class.

1.3. Using setUp() Method to Manage Test Pre-requisites.

A <setUp()> method works as an entry point for the test cases. We can use it to run a fixed set of actions before executing a test or all the tests defined in the class.

These are pre-requisites which may include the following test setup preparation tasks.

1. Create an instance of a browser driver.
2. Navigate to a base URL.
3. Load tests data for execution.
4. Open log files for recording inputs, statuses, and errors.

This method takes no arguments and doesn’t return anything. If a script has the setUp() method defined, then the runner will call it first before running any of the test handlers.

In our example, we are using the setUp() method to create an instance of Firefox, setup the properties, and navigate to the main page of the application before executing the actual test.

 

2. Start Writing Selenium Python Test Scripts Using Unittest.

2.1. Create Your First Selenium Test in Python with Unittest.

After creating a setUp() method, we can now write some tests to verify the application’s functionality. So, first of all, let’s define our use case.

Use Case – In this example, we will search for a text in google and verify if the search returns a list of items.

Similar to the <setUp()> method, test methods get implemented in the TestCase class. While adding these methods, it’s a good practice to prefix their names with the word test. Having such a name helps Test Runner distinguish between a test and other methods. Check out the below script to demonstrate the given Selenium Python example.

2.2. Define Cleanup Strategy to Free Resources Post Test Execution.

Once the test execution finishes, the pre-requisites specified in the setUp() method have to be cleaned up.

So to achieve this, the base TestCase class provides another method i.e. tearDown() which the runner calls after test execution. It lets us clean the values initialized at the beginning of test via setUp() method.

In our example, when the test execution ends, we no longer need the instance of Firefox. So we will close it in the tearDown() method, as shown in the following code.

2.3. How to Execute the Test Case from Commandline?

Running the tests from the command line would require us to add a call to the main() method in the test script. We’ll also pass a verbosity argument to the main(). It’ll get the test result details displayed on the console.

Below is the piece of code to facilitate command line execution. We’ll need to add it in our test script towards the end.

After adding these lines, save the test as a standard Python script and name it as <selenium-python-test.py>. Then, try to execute it from the command line by using the following command.

After running the tests, the results would get displayed on the console along with the execution summary as captured in the following screenshot.

First Selenium Python Test Case

First Selenium Python Test Case

In addition to the results summary, there is a block of text getting printed as well to describe what went wrong. Look at the following screenshot to see what happens when we change the expected value (11 to 10) to something else.

Print Error Text in Selenium Python Test Case

Print Error Text in Selenium Python Test Case

As you can see from the logs, it’s easy to find the culprit test method that generated the failure. Use the backtrace to track down the code flow that led to the failure. Also, there is an AssertionError thrown after detecting a mismatch between expected and the actual output.

2.4. Add One More Selenium Python Test Case.

So far, we’ve automated one simple test case. But we can add as many cases as expected in the TestCase class. It’ll also help in creating logical groups of tests that are related to a specific functionality. So let’s add another test to the TestCase class. Name the new method starting with the word test, as shown in the following code.

Executing the TestClass would result in first opening and then closing the two instances of Firefox. That’s how the setUp() and tearDown() methods work for each test method. You can tally the results from the snapshot attached below.

Write Selenium Python Test Cases Using Unittest

Write Selenium Python Test Cases Using Unittest

2.5. Refactoring setUp() and tearDown() Methods for Optimization.

In the previous examples, we were using the setUp() method for creating instances of Firefox driver. But this approach was leading to the creation of a new instance of the web browser every time a new test case ran.

It was the setUp() method which was causing this behavior as it runs before every test case. The Same case is with the tearDown() method which triggers for every test case after it finishes executing.

So we can refactor our script to minimize the resource usage. It means that we can share a single Firefox instance between the methods instead of creating a new instance every time.

It’s possible by using the setUpClass() and tearDownClass() methods along with the @classmethod decorator. These methods enable us to set the values at the class level rather than at method level. The values initialized at class level are shared between the test methods.

Let’s see the above example with modified code to call the setUpClass() and tearDownClass() methods with the @classmethod decorator.

Selenium Python Test Script Example.

Upon executing the test, we can see that both the tests are getting run in the same Firefox browser.

3. Assertions in Python Unittest Framework.

The TestCase class of the Python Unittest library implements a list of assert methods. We can use them to match actual values returned by the application with the expected values. With every method, we can specify a condition that must be true for continue executing the test.

Following three types of assert are available.

1. Checking equivalence.
2. Logical comparison.
3. Acting in the case of Exceptions.

While running a test, the execution moves to next line only if the given assertion passes. Otherwise, the test would halt immediately prompting with a failure message.

Let’s look at an important list of assert methods.

List of Assert Methods in Python Unittest Module.

Assert Method

 Test Condition

Summary

assertEqual(a, b [,msg])

a==b

Check whether or not “a” and “b” match with each other. You can also pass a cusotm error message.

e.g. assertEqual(element.text,”10″)

assertNotEqual(a,b[,msg])

a!=b

assertTrue(x[,msg]))

bool(x) is True

Verify if the given expression evaluates to True or False.

e.g. assertTrue(element.is_displayed())

assertFalse(x[,msg]))

bool(x) isFalse

assertIsNot(a, b[,msg]))

a is not b

assertRaises(exc, fun,

*args, **kwds)

fun(*args,**kwds)

raises exc

Check whether the test step raises the specific Exception mentioned. One such example is to use this method to check <NoSuchElementFoundexception>.

assertRaisesRegexp(exc,

r, fun, *args, **kwds)

fun(*args,**kwds)raises excand themessagematchesregex r

assertAlmostEqual(a, b)

round(a-b,7) == 0

It compares the numeric values after rounding them to the number in the second argument.

assertNotAlmostEqual(a,b)

round(a-b,7) != 0

assertGreater(a, b)

a > b

These methods are similar to the assertEqual() method.

assertGreaterEqual(a,b)

a>=b

assertLess(a,b)

a<b

assertLessEqual(a,b)

a<=b

assertRegexpMatches(s, r)

r.search(s)

Verify whether a regexpsearch matches the text.

assertNotRegexpMatches(s, r)

not r.search(s)

assertMultiLineEqual(a,

b)

strings

This method is an extension to the assertEqual(), designed for multilinestrings.

assertListEqual(a, b)

lists

This method checks whether the lists “a” and “b” match. It helps to work with the drop-down fields.

fail()

 

This method fails the test unconditionally. It allows the creation of custom conditional blocks.

4. Create Selenium Python Test Suite Using Unittest.

The Unittest module has a TestSuite class which makes it easy to create an end to end Selenium Python Test Suite. With this feature, we can combine various tests into logical groups and turn them into a unified test suite. All of this is achievable by using the TestSuite, TestLoader, and TestRunner classes.

Before we get into details of TestSuite, let’s add a new test to check the home page of the application under test. We’ll aggregate this test along with the previous search tests into a single test suite, as shown in the following code.

Selenium Python Test Script Example.

4.1. Group Test Cases into a Test Suite.

You would have now very well understood that we’ll use the TestSuite class for defining and running the test suite. And we can add multiple test cases into it. Also, apart from the TestSuite class, we need to use TestLoader and TextTestRunner classes to create and run a test suite. Please refer the below code.

4.2. Execute the Test Suite.

The TestLoader class reads all the test methods from the specified test files that contain the definition of the test suite. Then, the TestRunner class take control of the test suite and run all the tests specified. Below is the command to run the new test suite script.

It’ll run all the tests from the SearchText and HomePage classes and generate the following output.

First Selenium Python Test Case

First Selenium Python Test Case

5. Generate HTML Test Suite Execution Report.

By default, the Python Unittest library emits the test output on the terminal console. If you want to share the results with management and stakeholders, then sending console logs isn’t the appropriate way.

So you need to generate a report which looks presentable and professional. A summary report formatted nicely, with a drill-down access to the details is what required.

Since the unit test library doesn’t have the ability to produce such report, so you should use the HTMLTestRunner extension.

To download the HTMLTestRunner, please follow the below link.

+ Download HTMLTestRunner Module

 

 

To integrate HTMLTestRunnersupport in our test script, we need to create an output file to store the actual report, configure the HTMLTestRunner options, and run the tests in the following manner.

Selenium Python Test Suite Example.

After executing the test suite, we’ll see that HTMLTestRunner runs all the tests as does the test runner of the unit test library. At the end of the test, it’ll produce a report file as captured in the following snapshot.

Selenium Python Test Suite With HTML Report

Selenium Python Test Suite With HTML Report

You can now look at the attached HTML report and see that it’s presenting all the required details of test execution. From the failure links, you can even drill down the actual problem. Overall, it’s a nice looking report which you can proudly share with all the stakeholders.

We hope you’d enjoyed reading this tutorial.

Have a great day!

TechBeamers.

3 Comments

  1. Andrii Reply
    • Andrii Reply

Leave a Reply


*