天天看点

pytest实战--参数化parametrize+前置fixture

文章目录

        • 参数化 parametrize
          • 适用场景
          • 一个典型的例子
        • 前置fixture+参数化
          • 适用场景
          • 一个典型的例子
          • 示例2
        • 个人疑问?

pytest既可以用来做单元测试,也可以用来做自动化接口测试,pytest可以结合allure生成漂亮的测试报告,经过一段时间的学习,记录下在单元测试中用到的比较常用的方法

参数化 parametrize

适用场景

在学习pytest的时候学的时候用的最多且最先学习的是参数化,

  • 他的应用场景是:比如我需要用自己设计的用例来调用某一个函数多次,当我设计了10个不同的用例,那么我就需要调用十次函数。
  • 以常规的思路想,循环也可以做到啊。但是pytest有参数化这个强大的功能。
一个典型的例子
# content of test_expectation.py

# coding:utf-8

import pytest
#这里设置了三组测试用例,每组用例用()来表示,用例之间用“,”隔开
@pytest.mark.parametrize("test_input,expected",
                         [ ("3+5", 8),
                           ("2+4", 6),
                           ("6 * 9", 42),
                         ])
def test_eval(test_input, expected):  #此处用参数化命名的参数名
    assert eval(test_input) == expected

#
if __name__ == "__main__":
    pytest.main(["-s", "test_canshu1.py"])
           

运行结果:

================================== FAILURES ===================================
_____________________________ test_eval[6 * 9-42] _____________________________

test_input = '6 * 9', expected = 42

    @pytest.mark.parametrize("test_input,expected",
                             [ ("3+5", 8),
                               ("2+4", 6),
                               ("6 * 9", 42),
                             ])
    def test_eval(test_input, expected):
>       assert eval(test_input) == expected
E       AssertionError: assert 54 == 42
E        +  where 54 = eval('6 * 9')

test_canshu1.py:11: AssertionError
===================== 1 failed, 2 passed in 1.98 seconds ======================
           

前置fixture+参数化

适用场景

在继参数化之后用到的一个功能强大的是前置fixture

  • 应用场景1:用例1需要先登录,用例2不需要登录,用例3需要

    先登录

  • 应用场景2:比如说你需要实例化一个类之后再分别调用里面的各个函数,而且是需要在实例化的时候传入几个不同的用例(参数化解决)
  • 以常规的做法来做场景2,需要在每个函数调用的时候都实例化一次,所以fixture前置来做实例化(例2会有示例)
一个典型的例子
# coding:utf-8

import pytest

# 不带参数时默认scope="function"
@pytest.fixture()
def login():
    print("输入账号,密码先登录")

def test_s1(login):
    print("用例1:登录之后其它动作111")

def test_s2():  # 不传login
    print("用例2:不需要登录,操作222")

def test_s3(login):
    print("用例3:登录之后其它动作333")

if __name__ == "__main__":
    pytest.main(["-s", "test_fix.py"])

           

运行结果:

============================= test session starts =============================
platform win32 -- Python 3.6.0, pytest-3.6.3, py-1.5.4, pluggy-0.6.0
rootdir: E:\YOYO, inifile:
collected 3 items

test_fix.py 输入账号,密码先登录
用例1:登录之后其它动作111
.用例2:不需要登录,操作222
.输入账号,密码先登录
用例3:登录之后其它动作333
.

========================== 3 passed in 0.06 seconds ===========================
           
示例2
#coding = utf-8
import os,re
import sys
lib_path = os.path.abspath(os.path.join('E:\测试项目\models'))
sys.path.append(lib_path)
import pytest
import dataModel as A
import logging
import pandas as pd
import numpy as np
from utils.type_processing import stringToTime

logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s')

#五个需要测试的用例,参数化需要用到的参数
data = [("E:\测试项目\讲话.xlsx"),
         ("E:\测试项目\党章党规目录(2019年6月26日版).xls"),
         ("E:\测试项目\lilun.txt"),
         ("E:\\测试项目\\test1.xlsx"),
         ("E:\\测试项目\\test1.txt")]

#前置fixture,范围为module,代表每个class执行一次
@pytest.fixture(scope = "module")
def a(request):
	filepath = request.param
	x = A.DataModel(filepath)  #此处是实例化
	print("现在测试的是文件 %s" % filepath)
	return x


#参数化,把上面五个用例传入,a代表前置fixture
@pytest.mark.parametrize("a",data,indirect=True)
class TestData(object):

	#存在title的文件
	def test_title(self,a):
		C = a  
		if C.df.empty:
			print("文件为空")
		else:
			msg = "文件的标题为空"
			title = C.extract_title()
			assert title != -1,msg

	def test_author(self,a):
		C = a
		if C.df.empty:
			print("文件为空")
		else:
			msg = "文件的作者为空"
			author = C.extract_author()
			assert author != -1,msg


	def test_content(self,a):
		C = a
		if C.df.empty:
			print("文件为空")
		else:
			#msg = "文件的标题为空"
			content = C.extract_content()
			assert content is not None

	def test_time(self,a):
		C = a
		if C.df.empty:
			print("文件为空")
		else:
			msg = "文件的时间为空"
			time = C.extract_time()
			assert time != -1,msg
           
为什么参数化函数@pytest.mark.parametrize("a",data,indirect=True) 
参数a为前置fixture?

解答:注意在参数化那里写了一个indirect=True的参数,所以前面“a”为前置,后面的data为参数化的参数名。
           

个人疑问?

  • pytest的应用场景那么广,但是为什么网上的单元测试的代码或者博文却很少,大多数都是做的接口自动化?
  • 如果pytest应用于单元测试,那么断言对于我来说,通常是一个比较大的障碍,因为大多时候一个函数的输出,在用参数化的时候,输出的结果不能用统一的assert来做出判断。
  • 单元测试似乎不受到特别的重视,或者说一个项目没有完整的单元测试?
  • 还需努力呀!