Python 面试:单元测试unit testing & 使用pytest

1. 对于函数进行单元测试

calc.py

python 复制代码
def add(x, y):
    """Add Function"""
    return x + y

def subtract(x, y):
    """Subtract Function"""
    return x - y

def multiply(x, y):
    """Multiply Function"""
    return x * y

def divide(x, y):
    """Divide Function"""
    if y == 0: 
        raise ValueError('Can not divide by zero!')
    return x / y

test_calc.py

python 复制代码
import unittest
import calc

class TestCalc(unittest.TestCase):

    def test_add(self):
        self.assertEqual(calc.add(10, 5), 15)
        self.assertEqual(calc.add(-1, 1), 0)
        self.assertEqual(calc.add(-1, -1), -2)

    def test_subtract(self):
        self.assertEqual(calc.subtract(10, 5), 5)
        self.assertEqual(calc.subtract(-1, 1), -2)
        self.assertEqual(calc.subtract(-1, -1), 0)

    def test_multiply(self):
        self.assertEqual(calc.multiply(10, 5), 50)
        self.assertEqual(calc.multiply(-1, 1), -1)
        self.assertEqual(calc.multiply(-1, -1), 1)

    def test_divide(self):
        self.assertEqual(calc.divide(10, 5), 2)
        self.assertEqual(calc.divide(-1, 1), -1)
        self.assertEqual(calc.divide(-1, -1), 1)

        self.assertRaises(ValueError, calc.divide, 10, 0)


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

2. 对于对象(object)进行单元测试

employee.py

python 复制代码
class Employee:
    """A sample Employee class"""

    raise_amt = 1.05

    def __init__(self, first, last, pay):
        self.first = first
        self.last = last
        self.pay = pay

    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)
    
    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)
    
    def apply_raise(self):
        self.pay = int(self.pay * self.raise_amt)

test_employee.py

python 复制代码
import unittest
from employee import Employee

class TestEmployee(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print('setupClass')

    @classmethod
    def tearDownClass(cls):
        print('teardownClass')

    def setUp(self):
        print('setUp')
        self.emp_1 = Employee('Elon', 'Musk', 50000)
        self.emp_2 = Employee('Sue', 'Smith', 60000)

    def tearDown(self):
        print('tearDown\n')

    def test_email(self):
        print('test_email')
        self.assertEqual(self.emp_1.email, 'Elon.Musk@email.com')
        self.assertEqual(self.emp_2.email, 'Sue.Smith@email.com')

        self.emp_1.first = 'John'
        self.emp_2.first = 'Jane'

        self.assertEqual(self.emp_1.email, 'John.Musk@email.com')
        self.assertEqual(self.emp_2.email, 'Jane.Smith@email.com')

    def test_fullname(self):
        print('test_fullname')
        self.assertEqual(self.emp_1.fullname, 'Elon Musk')
        self.assertEqual(self.emp_2.fullname, 'Sue Smith')

        self.emp_1.first = 'John'
        self.emp_2.first = 'Jane'

        self.assertEqual(self.emp_1.fullname, 'John Musk')
        self.assertEqual(self.emp_2.fullname, 'Jane Smith')

    def test_apply_raise(self):
        print('test_apply_raise')
        self.emp_1.apply_raise()
        self.emp_2.apply_raise()

        self.assertEqual(self.emp_1.pay, 52500)
        self.assertEqual(self.emp_2.pay, 63000)

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

输出为:

setupClass

setUp

test_apply_raise

tearDown

.setUp

test_email

tearDown

.setUp

test_fullname

tearDown

.teardownClass


Ran 3 tests in 0.001s

OK

3. 使用mock模拟对象库

employee.py

python 复制代码
import requests

class Employee:
    """A sample Employee class"""

    raise_amt = 1.05

    def __init__(self, first, last, pay):
        self.first = first
        self.last = last
        self.pay = pay

    @property
    def email(self):
        return '{}.{}@email.com'.format(self.first, self.last)
    
    @property
    def fullname(self):
        return '{} {}'.format(self.first, self.last)
    
    def apply_raise(self):
        self.pay = int(self.pay * self.raise_amt)

    def monthly_schedule(self, month):
        response = requests.get(f'http://company.com/{self.last}/{month}')
        if response.ok:
            return response.text
        else:
            return 'Bad Response!'

test_employee.py

python 复制代码
import unittest
from unittest.mock import patch
from employee import Employee

class TestEmployee(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        print('setupClass')

    @classmethod
    def tearDownClass(cls):
        print('teardownClass')

    def setUp(self):
        print('setUp')
        self.emp_1 = Employee('Elon', 'Musk', 50000)
        self.emp_2 = Employee('Sue', 'Smith', 60000)

    def tearDown(self):
        print('tearDown\n')

    # Test 1
    def test_email(self):
        print('test_email')
        self.assertEqual(self.emp_1.email, 'Elon.Musk@email.com')
        self.assertEqual(self.emp_2.email, 'Sue.Smith@email.com')

        self.emp_1.first = 'John'
        self.emp_2.first = 'Jane'

        self.assertEqual(self.emp_1.email, 'John.Musk@email.com')
        self.assertEqual(self.emp_2.email, 'Jane.Smith@email.com')

    # Test 2
    def test_fullname(self):
        print('test_fullname')
        self.assertEqual(self.emp_1.fullname, 'Elon Musk')
        self.assertEqual(self.emp_2.fullname, 'Sue Smith')

        self.emp_1.first = 'John'
        self.emp_2.first = 'Jane'

        self.assertEqual(self.emp_1.fullname, 'John Musk')
        self.assertEqual(self.emp_2.fullname, 'Jane Smith')

    # Test 3
    def test_apply_raise(self):
        print('test_apply_raise')
        self.emp_1.apply_raise()
        self.emp_2.apply_raise()

        self.assertEqual(self.emp_1.pay, 52500)
        self.assertEqual(self.emp_2.pay, 63000)

    # Test 4
    def test_monthly_schedule(self):
    	# 模拟替换网络请求
        with patch('employee.requests.get') as mocked_get:
            mocked_get.return_value.ok = True
            mocked_get.return_value.text = 'Success'

            schedule = self.emp_1.monthly_schedule('May')
            mocked_get.assert_called_with('http://company.com/Musk/May')
            self.assertEqual(schedule, 'Success')

            mocked_get.return_value.ok = False

            schedule = self.emp_2.monthly_schedule('June')
            mocked_get.assert_called_with('http://company.com/Smith/June')
            self.assertEqual(schedule, 'Bad Response!')

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

输出为:

setupClass

setUp

test_apply_raise

tearDown

.setUp

test_email

tearDown

.setUp

test_fullname

tearDown

.setUp

tearDown

.teardownClass


Ran 4 tests in 0.001s

OK

4. 使用pytest进行测试

binarysearch.py,主要使用assert。

python 复制代码
def binary_search(array, target):
    if not array:
        return -1
    begin, end = 0, len(array)
    while begin < end:
        mid = begin + (end - begin) // 2
        if array[mid] == target:
            return mid
        elif array[mid] > target:
            end = mid
        else:
            begin = mid + 1
    return -1

def test():
    assert binary_search([0, 1, 2, 3, 4, 5], 1) == 1
    assert binary_search([0, 1, 2, 3, 4, 5], 6) == -1
    assert binary_search([0, 1, 2, 3, 4, 5], -1) == -1

    assert binary_search([0, 1, 2, 3, 4, 5], 0) == 0
    assert binary_search([0, 1, 2, 3, 4, 5], 5) == 5
    assert binary_search([0], 0) == 0

    assert binary_search([], 1) == -1

在CMD中输入指令:pytest binarysearch.py

输出为:

================================================= test session starts =================================================

platform win32 -- Python 3.10.9, pytest-7.1.2, pluggy-1.0.0

rootdir: C:\Users\h13je\Working_Log\01092023\python_learning

plugins: anyio-3.5.0

collected 1 item

binarysearch.py . [100%]

================================================== 1 passed in 0.02s ==================================================

相关推荐
helloweilei12 小时前
python 抽象基类
python
Lee川12 小时前
深度解构JavaScript:作用域链与闭包的内存全景图
javascript·面试
用户83562907805112 小时前
Python 实现 PPT 转 HTML
后端·python
UrbanJazzerati14 小时前
Python Scrapling反爬虫小技巧之Referer
后端·面试
一点一一14 小时前
从输入URL到页面加载:浏览器多进程/线程协同的完整逻辑
前端·面试
暮色妖娆丶17 小时前
不过是吃了几年互联网红利罢了,我高估了自己
java·后端·面试
UrbanJazzerati18 小时前
Python Scrapling:小白也能轻松掌握的现代网页抓取工具
后端·面试
Lee川18 小时前
🚀《JavaScript 灵魂深处:从 V8 引擎的“双轨并行”看执行上下文的演进之路》
javascript·面试
zone773918 小时前
004:RAG 入门-LangChain读取PDF
后端·python·面试
zone773918 小时前
005:RAG 入门-LangChain读取表格数据
后端·python·agent