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 ==================================================

相关推荐
JAVA社区24 分钟前
Java高级全套教程(十)—— SpringCloudAlibaba超详细实战详解
java·开发语言·spring cloud·面试·职场和发展
弥树子30 分钟前
踩坑记录:服务器内网调用接口,真实请求URL与官方公开URL不一致问题排查
开发语言·php
voidmort31 分钟前
3. 微调(Fine-tuning)与强化学习(RL)的核心思想
python·深度学习·算法
z落落1 小时前
C# ToCharArray + foreach遍历 + String与StringBuilder
开发语言·c#
学代码的真由酱1 小时前
Java多用户一对一网页聊天室-测试报告
java·开发语言·功能测试·测试
biter down1 小时前
基于 Pywinauto 的 QQ 音乐 GUI 自动化测试实践
python
人道领域1 小时前
【LeetCode刷题日记】669.修剪二叉搜索树
开发语言·python·算法
xiaoshuaishuai82 小时前
C# AvaloniaUI动态显示图片
开发语言·c#
日光明媚2 小时前
一步生成视频!One-Forcing:DMD + 零成本 GAN,训练 200 步超越多步 SOTA
android·开发语言·kotlin
2301_803538952 小时前
Java读取Word图片的两种实用方法
java·开发语言·word