当前位置:网站首页>Unit test - unittest framework

Unit test - unittest framework

2022-07-06 11:55:00 mb61037a3723f67


One : Unittest Core elements :

1: Core element concept

  • TestCase: The test case


TestCase Inherited from unittest.TestCase
The test method must be test start


  • TestSuit: test suite


test suite : Integrating multiple test cases together is the test suite .
1: Instantiate the test suite suite = unittest.TestSuite()
2: Add test cases to the test suite suite.addTest(MyTest(‘test_xxx’))


  • TextTestRunner:


Test the actuator : Used to execute the test suite
1: Instantiate the test executor : runner = unittest.TextTestRunner()
2: Execute test suite : runner.run(suite)


  • FixTure: summary :


Pre and post methods are implemented in the test case class , Then this test class is a Fixture.
For example, the : setUp() and tearDown


2: Test flow chart :

 unit testing ----Unittest frame _html

3: Case demonstration execution process :

       
# 1: Guide pack
import unittest

# 2: Prepare test class
class MyTest(unittest.TestCase):
def test_1(self):
print(" This is a :test_1")

def test_2(self):
print(" This is a :test_2")


if __name__ == '__main__':

# 3: Add test cases to In the test suite .
# Instantiate the test suite
suite = unittest.TestSuite()
# Add test cases to the test suite .
suite.addTest(MyTest('test_1'))
suite.addTest(MyTest('test_2'))

# 4: Run the test cases in the container
# Instantiate the test executor
runner = unittest.TextTestRunner()
runner.run(suite)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.

demonstration :

 unit testing ----Unittest frame _html_02

4: defaultTestLoader: Test cases under the specified directory are automatically added to the test suite

       
# 1: Guide pack
import unittest

# 2: Prepare test class
class MyTest(unittest.TestCase):
def test_1(self):
print(" This is a :test_1")

def test_2(self):
print(" This is a :test_2")


if __name__ == '__main__':

# Set the test_1.demo.py All the test cases in are loaded into the test suite .
suite = unittest.defaultTestLoader.discover("./", "test_1_demo.py")
# Run test cases
runner = unittest.TextTestRunner()
runner.run(suite)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

Two : unittest Use

1:unittest Use steps

  • unittest The default order of loading scripts is : according to ASCII Code sequence loading , The order of numbers and letters is :0-9,A-Z,a-z
       
""" unittest Basic use of """

# 1: Import unittest package
import unittest

# 2: Create test case classes
class MyTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setUpClass")

@classmethod
def tearDownClass(cls):
print("tearDownClass")

def setUp(self):
print("setup")

def tearDown(self):
print("tearDown")

def test_s(self):
print("test_s")
a = 1 + 1
self.assertEqual(a, 2, " The result is not 2")

def test_b(self):
print("test_b")
b = 1 + 2
self.assertEqual(b, 2, " The result is not 2")

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

Running results :

 unit testing ----Unittest frame _ The test case _03

2: unittest The provided assertion function [ Look up the table ]

 unit testing ----Unittest frame _ Instantiation _04

 unit testing ----Unittest frame _html_05

 unit testing ----Unittest frame _html_06

 unit testing ----Unittest frame _ Instantiation _07

3: A parameterized :

problem : If a test case needs to pass parameters , How to deliver ??

1: Installation package :

       
pip install parameterized -i https://pypi.tuna.tsinghua.edu.cn/simple
  • 1.

2: Case study :

       
# 1: Guide pack
import unittest
from parameterized import parameterized

# 2: Create test class
class MyTest(unittest.TestCase):

@parameterized.expand([('renshanwen', 23), ('niuniu', 25)])
def test_param(self, name, age):
print("name: %s, age: %s" % (name, age))


if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

3: Running effect :

 unit testing ----Unittest frame _html_08

3、 ... and : mock Use :

1: mock Principle :

Mock yes Python A library for supporting unit testing in , Its main function is to use mock Object replaces the specified Python object , To simulate the behavior of the object .

 unit testing ----Unittest frame _html_09

2:mock Basic use of

return_value Use

Case study : Business needs : Because a piece of code has not been implemented , But you need to return a 250 The number of , You need to use mock Replace unimplemented code , Return to one 250 The number of , The purpose is to make the test process run smoothly .

       
# 1: Guide pack
import unittest
import unittest.mock

# 2: Create simulated classes
class MyTest(unittest.TestCase):

def test_return(self):
# Create one that can return 250 Callable object of
mock_obj = unittest.mock.Mock(return_value=250)
# call mocke object , Get the return value
ret = mock_obj()
print(ret)

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

 unit testing ----Unittest frame _html_10

side_effect Use :

1: utilize side_effect Pass an exception :

       
# 1: Guide pack
import unittest
import unittest.mock

# 2: Create simulated classes
class MyTest(unittest.TestCase):

def test_return(self):
# Create one that can return 250 Callable object of
mock_obj = unittest.mock.Mock(side_effect=BaseException(" Custom exception "))
# call mocke object , Get the return value
ret = mock_obj()
print(ret)

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

 unit testing ----Unittest frame _ The test case _11

2: Use side_effect Pass an array :

       
import unittest.mock

# 2: Create simulated classes
class MyTest(unittest.TestCase):

def test_return(self):
# Create one that can return 250 Callable object of
mock_obj = unittest.mock.Mock(side_effect=[1, 2, 3])
# call mocke object , Get the return value
for i in range(3):
print(mock_obj())


if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

 unit testing ----Unittest frame _html_12

3: Use side_effect Pass a function :

       
# 1: Guide pack
import unittest
import unittest.mock

# 2: Create simulated classes
class MyTest(unittest.TestCase):
def test_return(self):
def sum_ab(a, b):
return a + b
# Create one that can return 250 Callable object of
mock_obj = unittest.mock.Mock(side_effect=sum_ab)
# call mocke object , Get the return value
print(mock_obj(1, 2))

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

 unit testing ----Unittest frame _ The test case _13

mock The case of :

Business needs : Now there is a need : A Responsible for developing payment function , however A Not developed yet .B Responsible for the payment status module , Already completed ,B Call in code A Write the code of the payment function . Now ask C test B Whether the written code meets the requirements ,C How to test ??

answer : Use mock Replace A Write the function , And then call B When you write a function, you will call our mock, Not invoke A Unfinished code .

 unit testing ----Unittest frame _ Instantiation _14

       
import unittest
import unittest.mock
import pay
import pay_status

class TestPay(unittest.TestCase):
def test_success(self):
# Use one mock Instead of pay Medium pay_way function
pay.pay_way = unittest.mock.Mock(return_value={"result": "success", "reason":"null"})
# Embezzle the function to be tested
ret = pay_status.pay_way_status()
self.assertEqual(ret, ' Successful payment ', ' Failure to pay ')

def test_fail(self):
pay.pay_way = unittest.mock.Mock(return_value={"result": "fail", "reason":" Lack of balance "})

ret = pay_status.pay_way_status() # Call the payment status function
self.assertEqual(ret, ' Failure to pay ', ' Test to fail ')

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

 unit testing ----Unittest frame _html_15

mock Side effects :

Tips : When we use mock After dropping an object , By default , The code executed later will be affected , For example, other test cases , Other code , As long as these codes are in mock After that, the implementation will be affected .

       
import unittest
import unittest.mock
import pay
import pay_status

class TestPay(unittest.TestCase):
def test_success(self):
# Use one mock Instead of pay Medium pay_way function
pay.pay_way = unittest.mock.Mock(return_value={"result": "success", "reason":"null"})
# Embezzle the function to be tested
ret = pay_status.pay_way_status()
self.assertEqual(ret, ' Successful payment ', ' Failure to pay ')

def test_success2(self):
# Embezzle the function to be tested
ret = pay_status.pay_way_status()
self.assertEqual(ret, ' Successful payment ', ' Failure to pay ')

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

 unit testing ----Unittest frame _ Instantiation _16

For the above code ,test_success2, We didn't use it mock Instead of , The results also used mock. The reason is that mock Once used , The test cases executed later can only be used mock, You can't use the original function .

Limit mock There are only two ways to act on the current function

1: patch Decorator :


1: Add a decorator on it : @mock.patch(‘ Replaced function path ’)
2: Function adds another incoming value .
3: Directly use inside the function The name of the incoming value .return_value = { Return value key value pair }


       
import unittest
from unittest import mock

import pay
import pay_status

class TestPay(unittest.TestCase):

@mock.patch('pay.pay_way')
def test_success(self, mock_pay_way):
# Use one mock Instead of pay Medium pay_way function
mock_pay_way.return_value={"result": "success", "reason":"null"}
# Embezzle the function to be tested
ret = pay_status.pay_way_status()
self.assertEqual(ret, ' Successful payment ', ' Failure to pay ')

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

2: patch Context manager :


1: Function internal use : with mock.patch(‘ Replaced function path ’) as Alias :
2: Alias .return_value = { Return value key value pair }


       
import unittest
from unittest import mock

import pay
import pay_status

class TestPay(unittest.TestCase):
def test_success(self):
with mock.patch('pay.pay_way') as mock_pay_way:
# Use one mock Instead of pay Medium pay_way function
mock_pay_way.return_value={"result": "success", "reason":"null"}
# Embezzle the function to be tested
ret = pay_status.pay_way_status()
self.assertEqual(ret, ' Successful payment ', ' Failure to pay ')

if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

Replacement of class methods :

  • mock.patch.object( class , ‘ Method name ’) Returns the mock object
    What has just been replaced above are some functions , If you want to replace a function in a class, how to operate ???
       
from unittest import mock
import unittest

class Pay(object):
def pay_way(self):
""" Suppose this is a payment function , Not yet developed
Payment successful return :{"result": "success", "reason":"null"}
Payment failure returns :{"result": "fail", "reason":" Lack of balance "}
reason Return the failure reason
"""
raise NotImplementedError(' The code has not been implemented ')

def pay_way_status(self):
""" According to the result of the payment success or fail, Judge to jump to the corresponding page
Suppose the functions here have been developed """

# todo here pay_way() Function not completed ! Let's assume he's finished
result = self.pay_way()
print(result)

if result["result"] == "success":
return " Successful payment "
if result["result"] == "fail":
return " Failure to pay "
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

Scheme 1 : The traditional way :


1: Instantiate this class first
2: object . Replaced function = mock.Mock(return_value = { Returned key value pairs })
3: object . The function under test ()


       
class TestPayStatues(unittest.TestCase):
''' Unit Test Case '''

def test_success1(self):
''' Test payment success scenarios '''
p = Pay() # Instantiate objects
p.pay_way = mock.Mock(return_value = {"result": "success", "reason":"null"})
statues = p.pay_way_status()
print(statues)
self.assertEqual(statues, " Successful payment ")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

Option two : Decorator


1: Add decorators to the test function :@mock.patch.object( class , ‘ The name of the method being replaced ’)
2: Adding a function to pass values ,def test_success2(self, mock_obj):
3: Use the new value .return_value = { Returned key value pairs }
4: Instantiate the class . Tested function ()


       
class TestPayStatues(unittest.TestCase):
@mock.patch.object(Pay, 'pay_way')
def test_success2(self, mock_obj):
''' Test payment success scenarios '''
mock_obj.return_value = {"result": "success", "reason":"null"}
# Test page Jump based on payment results
statues = Pay().pay_way_status()
print(statues)
self.assertEqual(statues, " Successful payment ")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

Option three : Use whith Context


1: with mock.patch.object( class , ‘ The name of the method being replaced ’) as New name
2: New name .return_value = {}
3: Instantiate the class . Tested function ()


       
class TestPayStatues(unittest.TestCase):
def test_success3(self):
''' Test payment success scenarios '''
with mock.patch.object(Pay, 'pay_way') as mock_obj:
mock_obj.return_value = {"result": "success", "reason":"null"}
# Test page Jump based on payment results
statues = Pay().pay_way_status()
print(statues)
self.assertEqual(statues, " Successful payment ")
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.

mock Two properties of :


  • mock.called: decision mock Whether it has been called .
  • mock.call_count : decision mock Number of calls .

Case test :

       
import unittest
import unittest.mock


class MockTest(unittest.TestCase):

def test_return_value(self):
mock_obj = unittest.mock.Mock(return_value=1999)
result = mock_obj()
print(result) # Print 1999

print(mock_obj.called) # Whether it has been called , Returns a Boolean value
print(mock_obj.call_count) # Get call test , Return to call the test


if __name__ == '__main__':
unittest.main()
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

 unit testing ----Unittest frame _ Instantiation _17

Four : Test report

1:HTMLTestRunner

1: Installation package :

       
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple htmltestrunner-python3
  • 1.

2: Core code :

       
if __name__ == '__main__':
# 1. Add test cases to suite In the container
suite = unittest.defaultTestLoader.discover('./', 'test_1_html.py')

# 2. Open file , It's a file object
with open('./HTMLTestRunner.html', 'w', encoding='utf-8') as f:
# 3. HTMLTestRunner() Create a runner object
runner = HTMLTestRunner(
stream=f, # The file to which the test report needs to be written
verbosity=2, # The level of detail of the console output information , The default is 1
title=' This is the title of the report ', # Title of test report
description=' This is a test report ' # Description of test report
)
# 4. runner Run the test cases in the container
runner.run(suite)
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.

2: BeautifulReport

1: Installation package :

       
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple beautifulreport
  • 1.

2: Core code :

       
if __name__ == '__main__':
# 1. Add test cases to suite In the container
suite = unittest.defaultTestLoader.discover('./', 'test_2_beautiful.py')

# 2. establish runner object , At the same time suite Let's enter
runner = BeautifulReport(suite)

# 3. function , At the same time, generate test reports
# Parameters 1: Comments for the generated file , Parameters 2: Generate a file of filename, Parameters 3: Generate report File storage path for
runner.report(' The report description must have , Displayed in the report as the use case name ', ' Test report file name ', './')
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.



原网站

版权声明
本文为[mb61037a3723f67]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202131611249947.html