Unittest - Part 1


The unittest unit testing framework was originally inspired by JUnit and has a similar flavor as major unit testing frameworks in other languages. It 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.
unittest supports some important concepts in an object-oriented way:
test fixture
A test fixture represents the preparation needed to perform one or more tests, and any associated cleanup actions. This may involve, for example, creating temporary or proxy databases, directories, or starting a server process.
test case
A test case is the individual unit of testing. It checks for a specific response to a particular set of inputs. unittest provides a base class, TestCase, which may be used to create new test cases.
test suite
A test suite is a collection of test cases, test suites, or both. It is used to aggregate tests that should be executed together.
test runner
A test runner is a component which orchestrates the execution of tests and provides the outcome to the user. The runner may use a graphical interface, a textual interface, or return a special value to indicate the results of executing the tests.
Basic Example – SimpleAdd.py
import unittest

class simpleTest(unittest.TestCase):
   
def testAdd(self):
        a=
10
       
b=20
       
c=a+b
       
self.assertEqual(c,30)

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

The following steps are involved in writing a Basic unit test −

Step 1 − Import the unittest module in your program.
Step 2 − Create a testcase by subclassing unittest.TestCase.
Step 3 − Define a test as a method inside the class. Name of method must start with 'test'.
Step 4 − Each test calls assert function of TestCase class. There are many types of asserts. Following example calls assertEquals() function.
Step 5 − assertEquals() function compares result of add() function with arg2 argument and throws assertionError if comparison fails.
Step 6 − Finally, call main() method from the unittest module.

How to run python unittest module

If you’re using PyCharm IDE, you can simply press ctrl+shift+F10 to run unittest module.

Output will be
you can use command prompt to run this module. Open up a terminal and navigate to the folder that contains your test module(simpleAdd.py):

Passing the -v option to enable a higher level of verbosity, and produce the following output:

There are three types of possible test outcomes :
OK – means  all the tests are passed.
FAIL – means test did not pass and an AssertionError exception is raised.
ERROR – means test raises an exception other than AssertionError.

These outcomes are displayed on the console by '.', 'F' and 'E' respectively.

.(DOT) means Pass
F means Fail
E means Error

unittest supports the following command line options.
1)-h, --help
Show this message

2)-v, --verbose
Verbose output

3)-q, --quiet
Minimal output

4)-f, --failfast
Stop on first failure

5)-c, --catch
Catch control-C and display results

6)-b, --buffer
Buffer stdout and stderr during test runs

Ex: python simpleAdd.py -q
TestFixtures
Fixtures are resources needed by a test. For example, if you are writing several tests for the same class, those tests all need an instance of that class to use for testing. Other test fixtures include database connections and temporary files. TestCase includes a special hook to configure and clean up any fixtures needed by your tests. To configure the fixtures, override setUp(). To clean up, override tearDown().Test fixtures are methods and functions that run before and after a test.

In the following example, one test is written inside the TestCase class. The test is to loginApp into application . The setup() method will launch the chrome browser of each test and the  teardown() method will be executed at the end of each test.
Script:
from selenium import webdriver
import unittest
from selenium.webdriver.common.by import By


class testFixture(unittest.TestCase):
    driver=
""

   
def setUp(self):
        base_url =
"http://automationpractice.com/"
       
chromePath = "C:\\executables\\chromedriver.exe"
       
self.driver = webdriver.Chrome(executable_path=chromePath)
       
self.driver.get(base_url)

   
def testLoginApp(self):
       
LoginLink = (By.XPATH, "//a[@title='Log in to your customer account']")
       
UserName = (By.XPATH, "//input[@id='email']")
       
PassWord = (By.XPATH, "//input[@name='passwd']")
       
LoginBtn = (By.XPATH, "//button[@type='submit' and @id='SubmitLogin']")
       
self.driver.find_element(By.XPATH,"//a[@title='Log in to your customer account']").click()
       
self.driver.find_element(By.XPATH, "//input[@id='email']").send_keys("abc111@gmail.com")
       
self.driver.find_element(By.XPATH, "//input[@name='passwd']").send_keys("abcd1234")
       
self.driver.find_element(By.XPATH, "//button[@type='submit' and @id='SubmitLogin']").click()
       
self.driver.implicitly_wait(50)
        titleTxt=
self.driver.title
       
self.assertEqual(titleTxt,"My account - My Store")
def tearDown(self):
        self.driver.quit()
if __name__=="__main__":
    unittest.main()

Class Fixture
TestCase class has a setUpClass() method which can be overridden to execute before the execution of individual tests inside a TestCase class. Similarly, tearDownClass() method will be executed after all test in the class. Both the methods are class methods.

from selenium import webdriver
import unittest
from selenium.webdriver.common.by import By

class simpleClassFixtures(unittest.TestCase):
   
@classmethod
   
def setUpClass(cls):
       
print("setup at Class level")
        base_url =
"http://automationpractice.com/"
       
chromePath = "C:\\executables\\chromedriver.exe"
       
cls.driver = webdriver.Chrome(executable_path=chromePath)
       
cls.driver.get(base_url)

   
def testLoginApp(self):
       
LoginLink = (By.XPATH, "//a[@title='Log in to your customer account']")
       
UserName = (By.XPATH, "//input[@id='email']")
       
PassWord = (By.XPATH, "//input[@name='passwd']")
       
LoginBtn = (By.XPATH, "//button[@type='submit' and @id='SubmitLogin']")
       
self.driver.find_element(By.XPATH,"//a[@title='Log in to your customer account']").click()
       
self.driver.find_element(By.XPATH, "//input[@id='email']").send_keys("abc111@gmail.com")
       
self.driver.find_element(By.XPATH, "//input[@name='passwd']").send_keys("abcd1234")
       
self.driver.find_element(By.XPATH, "//button[@type='submit' and @id='SubmitLogin']").click()
       
self.driver.implicitly_wait(50)
        titleTxt=
self.driver.title
       
self.assertEqual(titleTxt,"My account - My Store")
   
def testsingOut(self):
       
self.driver.find_element(By.XPATH,"//a[@title='Log me out']").click()
        titleTxt =
self.driver.title
       
self.assertEqual(titleTxt, "Login - My Store")
       
print(titleTxt)
   
@classmethod
   
def tearDownClass(cls):
       
cls.driver.quit()
       
print("TearDown at Class Level")
if __name__=="__main__":
    unittest.main()

Although setUp() and tearDown() are the methods that allow us to make sure each test can run independently and in any order.

List of fixture methods are
setUp() / tearDown() – before and after test methods
setUpClass() / tearDownClass() – before and after a class of tests
setUpModule() / tearDownModule() – before and after a module of tests

Note: If an exception is raised in a setUpModule/setUpclass/setUp then none of the tests in the module/class will be run and the tearDownModule/tearDownclass/
tearDown will not be run.

Assertions
Python testing framework uses Python's built-in assert() function which tests a particular condition. If the assertion fails, an AssertionError will be raised. The testing framework will then identify the test as Failure. Other exceptions are treated as Error. All the assert methods accept a msg argument that, if specified, is used as the error message on failure

The following lists the most commonly used assert methods
1.   assertEqual(first, second, msg=None)
Test that first and second are equal. If the values do not compare equal, the test will fail.

2.   assertNotEqual(first, second, msg=None)
Test that first and second are not equal. If the values do compare equal, the test will fail.

3.   assertTrue(expr, msg=None)
Test that expr is true

4.   assertFalse(expr, msg=None)
Test that expr is false

5.   assertIs(first, second, msg=None)
Test that first and second evaluate to the same object.

6.   assertIsNot(first, second, msg=None)
Test that first and second don’t evaluate to the same object.
7.   assertIsNone(expr, msg=None)
Test that expr is None.

8.   assertIsNotNone(expr, msg=None)
Test that expr  is not None.

9.   assertIn(first, second, msg=None)
Test that first is in second.

10.assertNotIn(first, second, msg=None)
Test that first  is not in second.

11.assertIsInstance(obj, cls, msg=None)
Test that obj is (or is not) an instance of cls (which can be a class or a tuple of classes, as supported by isinstance()). To check for the exact type, use assertIs(type(obj), cls).

12.assertNotIsInstance(obj, cls, msg=None)
Test that obj  is not an instance of cls (which can be a class or a tuple of classes, as supported by isinstance()). To check for the exact type, use assertIs(type(obj), cls).

Few of the basic assertion methods are implemented in the below script.

import unittest

class simpleBasicAssert(unittest.TestCase):
   
def testBasicAssert(self):
# Statement 1
       
self.assertEqual(6 - 2, 4)
# Statement 2
       
self.assertNotEqual((10*2),21)
# Statement 3
       
self.assertTrue(4 + 5 == 9, "The result is False")
# Statement 4
       
self.assertTrue(4 + 5 == 10, "4 + 5 == 10 assertion fails")
# Statement 5
       
self.assertIn(3, [1, 2, 3])
# Statement 6
       
self.assertNotIn(3, range(5))
# Statement 7
       
self.assertIs(1, [1, 2, 3])

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

When the above script is run, Statement 4 will show failure and others run successfully.

There are also other methods used to perform more specific checks
1.   assertAlmostEqual(first, second, places=7, msg=None, delta=None)
Test that first and second are approximately equal by computing the difference, rounding to the given number of decimal places (default 7), and comparing to zero. Note that these methods round the values to the given number of decimal places (i.e. like the round() function) and not significant digits. If delta is supplied instead of places then the difference between first and second must be less or equal to (or greater than) delta.

2.   assertNotAlmostEqual(first, second, places=7, msg=None, delta=None)
Test that first and second are  not approximately equal by computing the difference, rounding to the given number of decimal places (default 7), and comparing to zero. Note that these methods round the values to the given number of decimal places (i.e. like the round() function) and not significant digits. If delta is supplied instead of places then the difference between first and second must be less or equal to (or greater than) delta.

3.   assertGreater(first, second, msg=None)

4.   assertGreaterEqual(first, second, msg=None)

5.   assertLess(first, second, msg=None)

6.   assertLessEqual(first, second, msg=None)
Test that first is respectively >, >=, < or <= than second depending on the method name. If not, the test will fail.

7.   assertRegex(text, regex, msg=None)
Test that a regex search matches text. In case of failure, the error message will include the pattern and the text. regex may be a regular expression object or a string containing a regular expression suitable for use by re.search().

8.   assertNotRegex(text, regex, msg=None)
Test that a regex search  does not match text. In case of failure, the error message will include the pattern and the part of text that unexpectedly matched. regex may be a regular expression object or a string containing a regular expression suitable for use by re.search().

9.   assertCountEqual(first, second, msg=None)
Test that sequence first contains the same elements as second, regardless of their order. When they don’t, an error message listing the differences between the sequences will be generated.
Duplicate elements are not ignored when comparing first and second. It verifies whether each element has the same count in both sequences. Equivalent to: assertEqual(Counter(list(first)), Counter(list(second))) but works with sequences of unhashable objects as well.

Few Assert methods are implemented in the below script
import unittest
import math
import re

class SimpleCheckAssertTest(unittest.TestCase):
  
def test1(self):
     
self.assertAlmostEqual(22.0/7,3.14)
  
def test2(self):
     
self.assertNotAlmostEqual(10.0/3,3)
  
def test3(self):
     
self.assertGreater(math.pi,3)

  
def test4(self):
      
self.assertNotRegexpMatches("Automation Frame work using UnitTest in Python ", "Frame")

  
def test5(self):
     
self.assertNotRegexpMatches("Automation Frame work using UnitTest in Python ","Frame")

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

The above script reports test1 and test5 as Failure.

The list of type-specific methods automatically used by assertEqual()
1.   assertMultiLineEqual(first, second, msg=None)
Test that the multiline string first is equal to the string second. When not equal a diff of the two strings highlighting the differences will be included in the error message. This method is used by default when comparing strings with assertEqual().

2.   assertSequenceEqual(first, second, msg=None, seq_type=None)
Tests that two sequences are equal. If a seq_type is supplied, both first and second must be instances of seq_type or a failure will be raised. If the sequences are different an error message is constructed that shows the difference between the two.
This method is not called directly by assertEqual(), but it’s used to implement assertListEqual() and assertTupleEqual().

3.   assertListEqual(first, second, msg=None)
Tests that two lists are equal. If not, an error message is constructed that shows only the differences between the two. An error is also raised if either of the parameters are of the wrong type. These methods are used by default when comparing lists with assertEqual().

4.   assertTupleEqual(first, second, msg=None)
Tests that two tuples are equal. If not, an error message is constructed that shows only the differences between the two. An error is also raised if either of the parameters are of the wrong type. These methods are used by default when comparing tuples with assertEqual().

5.   assertSetEqual(first, second, msg=None)
Tests that two sets are equal. If not, an error message is constructed that lists the differences between the sets. This method is used by default when comparing sets or frozensets with assertEqual().
Fails if either of first or second does not have a set.difference() method.

6.   assertDictEqual(first, second, msg=None)
Test that two dictionaries are equal. If not, an error message is constructed that shows the differences in the dictionaries. This method will be used by default to compare dictionaries in calls to assertEqual().

Few of the assert methods are implemented in the below script
import unittest

class SimpleCoolectionAssertTest(unittest.TestCase):
  
def test1(self):
     
self.assertListEqual([2,3,4], [1,2,3,4,5])
  
def test2(self):
     
self.assertTupleEqual((1*2,2*2,3*2), (2,4,6))
  
def test3(self):
         
self.assertDictEqual({1,2,3,4},{1,2,3,5})
  
def test4(self):
      
self.assertDictEqual({1: 11, 2: 22}, {3: 33, 2: 22, 1: 11})

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

In the above example, test1 , test3 and test4 show AssertionError. Error message displays the differences in List ,set and Dictionary objects.

Comments