Unit Test - Part 2


Skipping tests and expected failures
Skip Test
Unittest supports skipping individual test methods and even whole classes of tests conditionally as well as unconditionally. Skipping a test is simply a matter of using the skip() decorator or one of its conditional variants, calling TestCase.skipTest() within a setUp() or test method, or raising SkipTest directly.
Basic skipping method unconditionally.
import unittest

class SkipTestExample(unittest.TestCase):

   
@unittest.skip("Method not yet ready for execution")
   
def test_Skipp(self):
       
print("This is unconditionally Skipping Example")
   
def test_print(self):
       
print("This is will execute because skip method is not using")

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

When the above script is executed, the following result is displayed
Only “test_print()” method will execute and test_skip() method will not execute. 

The following decorators are implement test skipping:
1.   @unittest.skipIf(condition, reason)
Skip the decorated test if condition is true. 
Below is the example for skipIf decorators
import unittest
class SkipTestExample(unittest.TestCase):
    a=
10
   
b=20

   
def test_print(self):
       
print("This is will execute because skip method is not using")
   
@unittest.skipIf(a<b,"Skip this method if condition is met")
   
def test_skipif(self):
       
print("This method will execute only when a is greater then b else it will skip")

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

output will be

2.    @unittest.skipUnless(conditionreason)
Skip the decorated test unless condition is true.
Below is the script for skipUnless decorator

import unittest
class SkipTestExample(unittest.TestCase):
    a=
10
   
b=20

   
def test_print(self):
       
print("This is will execute because skip method is not using")

   
@unittest.skipUnless(a==0,"Skipping this method if condition is not met")
   
def test_skipif(self):
      
print("This method will execute only when a is not equal to 0 else it will skip")

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

Output will be

Expected Failure
It supports marking a test as an “expected failure,” a test that is broken and will fail, but shouldn’t be counted as a failure on a TestResult.
The following example demonstrates the use of expected failure.
import unittest
class ExpectedFailureExample(unittest.TestCase):

   
@unittest.expectedFailure
   
def test1_expectedFaliure(self):
        a=
5
       
b=6
       
self.assertEqual(a+b,10)

   
def test2_expectedFaliure(self):
        a =
5
       
b = 6
       
self.assertEqual(a + b, 10)

   
def test3(self):
        a =
5
       
b = 6
       
self.assertEqual(a + b, 11)
if __name__=="__main__":
    unittest.main()

Output will be


Test Suite Loading and running tests
To achieve this, unittest supports the following important concepts.
test suite − This is a collection of test cases, test suites, or both. This is used to aggregate tests that should be executed together. Test suites are implemented by the TestSuite class.
testLoader-The TestLoader class is used to create test suites from classes and modules. Normally, there is no need to create an instance of this class the unittest module provides an instance that can be shared as unittest.defaultTestLoader.
test runner − This is a component which organize the execution of tests and provides the results to end user. The runner may use a graphical interface, a textual interface, or return a special value to indicate the results of executing the tests.
Below is the example.
create simpleTestCase_1.py
# Test Suite
import unittest
class simpleTest1(unittest.TestCase):
    def setUp(self):

        print("Simple Test at Test level from simpleTest1")

   
def tearDown(self):
       
print("Simple Test TearDown from simpleTest1")

   
@unittest.expectedFailure
   
def testfirst(self):
        
self.assertTrue(10==20)

   
def testSecond(self):
       
print("simple TestSecond from simpleTest1")

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

create simpleTestCase_2.py
import unittest
class simpleTest2(unittest.TestCase):
   
@classmethod
   
def setUpClass(cls):
       
print("SetUp is class level simpleTest2")
   
    @classmethod
   
def tearDownClass(cls):
       
print("tearDown is at class level simpleTest2")
   
    def setUp(self):
       
print("\nTestlevel")

   
def testsimple(self):
       
print("simple Test simpleTest2")
   
    def testsimple1(self):
       
print("simpleTest2 simpleTest2")

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

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.

Create SimpleTestRunner.py 
import unittest
from simpleTestCase_1 import simpleTest1
from simpleTestCase_2 import simpleTest2

simple1=unittest.TestLoader().loadTestsFromTestCase(simpleTest1)
simple2=unittest.TestLoader().loadTestsFromTestCase(simpleTest2)
test_suite=unittest.TestSuite([simple1,simple2])
unittest.TextTestRunner(
verbosity=2).run(test_suite)

output will be


Generate HTML Test Suite Execution Report 
By default, the Python Unittest library send out the test output on the terminal console. If you want to share the results with management or stakeholders, console logs aren’t the appropriate way.
So, you need to generate human readable presentation of results in details what you required. Since the unit test library doesn’t have the ability to produce such a report, so you should use the HTMLTestRunner extension.

HtmlTest runner is a unittest test runner that saves results in a human-readable HTML format.
Note: for that you should install “html-testRunner” package.
HtmlTestRunner can also be used with test suites; just create a runner instance and call the run method with your suite.
Create SimpleHTMLTestRunner.py
import unittest
import HtmlTestRunner
from simpleTestCase_1 import simpleTest1
from simpleTestCase_2 import simpleTest2
simple1=unittest.TestLoader().loadTestsFromTestCase(simpleTest1)
simple2=unittest.TestLoader().loadTestsFromTestCase(simpleTest2)
test_suite=unittest.TestSuite([simple1,simple2])
outfile="C:\\PycharmProjects\\TestReport"
runner=HtmlTestRunner.HTMLTestRunner(outfile)
runner.run(test_suite)

This is a sample of the results from the template that came by default with the runner.
Note: By default, separate reports will be produced for each TestCase.

Combining Reports into a Single Report
By default, separate reports will be produced for each TestCase. The combine_reports boolean kwarg can be used to tell HTMLTestRunner to instead produce a single report:

Create SimpleHTMLTestRunner_combined.py

import unittest
import HtmlTestRunner
from simpleTestCase_1 import simpleTest1
from simpleTestCase_2 import simpleTest2
simple1=unittest.TestLoader().loadTestsFromTestCase(simpleTest1)
simple2=unittest.TestLoader().loadTestsFromTestCase(simpleTest2)
test_suite=unittest.TestSuite([simple1,simple2])
outfile="C:\\PycharmProjects\\TestReport"
runner=HtmlTestRunner.HTMLTestRunner(outfile,combine_reports=True)
runner.run(test_suite)

This is a sample of the combine reports of all the running testcases.

Setting a filename
By default the name of the HTML file(s) produced will be created by joining the names of each test case together. The report_name kwarg can be used to specify a custom filename. For example, the following will produce a report file called "MyReport.html":

runner=HtmlTestRunner.HTMLTestRunner(outfile,combine_reports=True,report_name="MyReport",add_timestamp=False)
Note:
if you are not add “add_timestamp=false” kwarg ,time stamp will concatenate   with your custom file name
Ex: MyReport_2019-11-04_14-19-24.html

if you are  add “add_timestamp=false” kwarg ,time stamp will not concatenate   with your custom file name
Ex: MyReport.html

Custom Templates
title: This is the report title - by default this is "Unittests Results" but can be changed using the report_title kwarg

Ex: runner=HtmlTestRunner.HTMLTestRunner(outfile,report_title="Regression",combine_reports=True)

Comments