Pytest : An Automation Testing Tool

Py.test is an alternative to unit test suite which provides more pythonic way of writing our tests. The overhead for creating unit tests is reduced almost to zero!

Jobs of Automated testing tools :

  • It verifies the code changes work outs.
  • Provides help when test fails, providing necessary details where and why the test failed.
  • It makes writing tests easy and fun.

Some fundamental features of Pytest are :

  • It’s cross project testing tool.
  • Provides useful information when tests fail.
  • no boiler plate (repetitive code) test code.
  • deep extensibilty
  • distribute tests to multiple hosts

Installing Pytest

$ pip install -U pytest       # or
$ easy_install -U pytest

Writing tests using pytest

In the previous post I showed how unittest test is used for testing by a taking a simple example of a calculator application.I am using the same example here to guide you thorough the basics of using pytest. Following is the code for calculator application.

# calculator.py

class Calculator:
    def add(self, x, y):
        return x + y

    def sub(self, x, y):
        return x - y

    def mul(self, x, y):
        return x * y

    def div(self, x, y):
        assert(y != 0);
        return x / y

The pytest code for this application is :


  # test_pytest_calculator.py

  class TestCalculator:
      def test_add(self, setup):
          cal = setup
          res = cal.add(10, 2)
          assert 12 == res

      def test_sub(self, setup):
          cal = setup
          res = cal.sub(7, 4)
          assert 3 == res

      def test_mul(self, setup):
          cal = setup
          res = cal.mul(5, 25)
          assert 125 == res

      def test_div(self, setup):
          cal = setup
          res = cal.div(20, 4)
          assert 5 == res

# conftest.py

from calculator import Calculator

def pytest_funcarg__setup(request):
    cal = Calculator()
    return cal

Now go to the command prompt in terminal and type the following command to run the test_calculator module

$ py.test test_calculator.py

for more verbose output use -v attribute.

$ py.test -v test_calculator.py

I am stopping myself here as am bit running out of time now.I will be updating this post soon with more topics showing skipping, expected to fail tests, marking a test and using some advanced plugins like Pep8, Pyflakes, codecheckers.
Happy Testing! cheers 🙂

Welcome back!

Here is an assert introspection for py.test


def test_assert_introspection():
    ''' with Unittest.py '''
    assert x        # assertTrue()
    assert x == 1   # assertEqual(x, 1)
    assert x != 2   # assertNotEqual(x, 2)
    assert not x    # assertFalse(x)

Marking Test functions/methods

py.test.mark.skipif(expression)                                    # for skipping tests

py.test.mark.xfail(expression)                                      # for expected to fail tests

py.test.mark.Name                                                          # use your own custom marking

Here is an example showing skipping test methods and xfail test methods:


# test_pytest_calculator.py
import py

class TestCalculator:
    def test_add(self, setup):
        cal = setup
        res = cal.add(10, 2)
        assert 12 == res

    @py.test.mark.skipif('True')
    def test_sub(self, setup):
        cal = setup
        res = cal.sub(7, 4)
        assert 3 == res

    @py.test.mark.xfail
    def test_mul(self, setup):
        cal = setup
        res = cal.mul(5, 25)
        assert 150 == res

    def test_div(self, setup):
        cal = setup
        res = cal.div(20, 4)
        assert 5 == res

Testing small project

Let’s do testing of a small scanner application which reads a file and looks for the url(s) present in the file and stores them in a separate list.
Following is the code for scanner application.


import urllib

class Scanner:
    def __init__(self, config):
        self.config = config

    def extract_urls(self, path):
        urls = []
        for line in path.readlines():
            line = line.strip()
            for urlprefix in self.config.urlprefixes:
                if line.startswith(urlprefix):
                    urls.append(line)
        return urls

and the py.test module for this application is :


import py
from myscan.scanner import Scanner

class config:
    pass

def test_extract_url(tmpdir):
    path=tmpdir.join('foo.ini')
    path.write("Testing Scanner\nhttp://pytest.org\nhttps://google.com\n")
    print path.read()
    con = config()
    con.urlprefixes = ['http://', 'https://']
    Scan = Scanner(con)
    urls = Scan.extract_urls(path)
    assert len(urls) == 2
    assert urls == ['http://pytest.org', 'https://google.com']

Some Advanced Plugins

py.test provides some important plugins, some of them which are most widely used are:

  • figleaf : It checks the test code coverage
  • codecheckers (pyflakes, pep8) : checks standardization of code, indentation, spacing etc and tells which of the modules where imported and not used etc to make code better.

Installing figleaf plugin

$ easy_install pytest-figleaf                       # or

$ pip install pytest-figleaf

Using figleaf plugin

$ py.test –figleaf test_module.py

Installing codecheckers plugin

$ easy_install pytest-codecheckers         # or

$ pip install pytest-codecheckers

Now let’s wind up this basic tutorial.Hope you all have enjoyed and will find testing interesting and fun.Happy testing! cheers 🙂

Advertisements

Unittest – Unit Testing Framework (Python)

Unit testing : It refers to the kind of testing where the tester refers to a small software module at a time and testing it in an isolated fashion.

Unittest supports test automation, sharing of setup and shutdown code for tests, aggregation of tests into collections, and independence of the tests from the reporting framework module.This module provides classes that make it easy to support these qualities for a set of tests.

Test Fixture : A test fixture is setting up well known and fixed environment in which tests are run so that to get a particular/expected  outcome.

A test is generally done in four phases.

Four Phases of a test are :

  • set up – It is used for setting up test fixture.
  • Exercise – interact with system under test.
  • verify – determine whether the expected outcome has been obtained.
  • Tear down – for cleanup of test fixture so that it returns to original state.

Note : Unit testing is a kind of white box testing.

Here I am giving a brief introduction  to unitttesting (python) so that those who wants to get started with software testing will find it interesting and easier.

I have taken a simple example of  a calculator application and will try to test it through unit testing frame work provided by unittest module in python.

# calculator.py

class Calculator:
def add(self, x, y):
return x + y

def sub(self, x, y):
return x - y

def mul(self, x, y):
return x * y

def div(self, x, y):
assert (y != 0)
        return x / y

The following is the unittest code for testing this calculator application.


# test_calculator.py

import unittest
from calculator import Calculator

class TestCalculator(unittest.TestCase):
def setUp(self):
self.cal = Calculator()

def test_add(self):
res = self.cal.add(10, 2)
self.assertEqual(12, res)

def test_sub(self):
res = self.cal.sub(7, 4)
self.assertEqual(3, res)

def test_mul(self):
res = self.cal.mul(5, 25)
self.assertEqual(125, res)

def test_div(self):
res = self.cal.div(20, 4)
self.assertEqual(5, res)

if __name__ == '__main__':
unittest.main()

In unittest framework we have to create a subclass of unittest TestCase as I have create in the above code. Here TestCalculator is the subclass of unittest TestCase class. The important thing to note here is that the name of the testcase class start with the word Test(i.e should follow this pattern ‘ Test*’ ) and the test methods name follows the pattern ‘ test* ‘. The methods test_add, test_sub, test_mul, test_div is used for testing add(), sub() , mul(), div() methods of Calculator class.Then setUp() method is used to create test fixture for the tests.

Skipping tests and Expected failures:

unittest provides methods for skipping test methods as well as test class and to mark a test as expected failures when we know that the test is going to fail.Here is an example code showing test skipping and expected failures.

# test_calculator.py

import unittest
from calculator import Calculator

class TestCalculator(unittest.TestCase):
def setUp(self):
self.cal = Calculator()

def test_add(self):
res = self.cal.add(10, 2)
self.assertEqual(12, res)

@unittest.skip("Demonstrating method skippping")
def test_sub(self):
res = self.cal.sub(7, 4)
self.assertEqual(12, res)

    @unittest.skipIf(2 > 0, "Demonstrating method skipping using skipIf")
def test_mul(self):
res = self.cal.mul(5, 25)
self.assertEqual(125, res)

@unittest.expectedFailure
def test_div(self):
res = self.cal.div(20, 4)
self.assertEqual(5, res)

if __name__ == '__main__':
unittest.main()