天天看點

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來做出判斷。
  • 單元測試似乎不受到特别的重視,或者說一個項目沒有完整的單元測試?
  • 還需努力呀!