Pytest - คู่มือฉบับย่อ

Pytest เป็นเฟรมเวิร์กการทดสอบที่ใช้ Python ซึ่งใช้ในการเขียนและรันโค้ดทดสอบ ในปัจจุบันของบริการ REST pytest ส่วนใหญ่จะใช้สำหรับการทดสอบ API แม้ว่าเราจะสามารถใช้ pytest เพื่อเขียนการทดสอบแบบง่ายไปจนถึงซับซ้อนได้เช่นเราสามารถเขียนโค้ดเพื่อทดสอบ API ฐานข้อมูล UI และอื่น ๆ

ข้อดีของ Pytest

ข้อดีของ Pytest มีดังนี้ -

  • Pytest สามารถเรียกใช้การทดสอบหลายรายการพร้อมกันซึ่งจะช่วยลดเวลาในการดำเนินการของชุดทดสอบ

  • Pytest มีวิธีของตัวเองในการตรวจจับไฟล์ทดสอบและทดสอบฟังก์ชันโดยอัตโนมัติหากไม่ได้ระบุไว้อย่างชัดเจน

  • Pytest ช่วยให้เราสามารถข้ามการทดสอบบางส่วนระหว่างการดำเนินการได้

  • Pytest ช่วยให้เราสามารถเรียกใช้ชุดทดสอบย่อยทั้งหมดได้

  • Pytest เป็นโอเพ่นซอร์สฟรี

  • เนื่องจากไวยากรณ์ที่เรียบง่าย pytest จึงเริ่มต้นได้ง่ายมาก

ในบทช่วยสอนนี้เราจะอธิบายถึงปัจจัยพื้นฐานที่ยิ่งใหญ่ที่สุดด้วยโปรแกรมตัวอย่าง

ในบทนี้เราจะเรียนรู้วิธีการติดตั้ง pytest

ในการเริ่มการติดตั้งให้ดำเนินการคำสั่งต่อไปนี้ -

pip install pytest == 2.9.1

เราสามารถติดตั้ง pytest เวอร์ชันใดก็ได้ นี่ 2.9.1 คือเวอร์ชันที่เรากำลังติดตั้ง

ในการติดตั้ง pytest เวอร์ชันล่าสุดให้ดำเนินการคำสั่งต่อไปนี้ -

pip install pytest

ยืนยันการติดตั้งโดยใช้คำสั่งต่อไปนี้เพื่อแสดงส่วนวิธีใช้ของ pytest

pytest -h

การเรียกใช้ pytest โดยไม่กล่าวถึงชื่อไฟล์จะเรียกใช้ไฟล์ทุกรูปแบบ test_*.py หรือ *_test.pyในไดเร็กทอรีปัจจุบันและไดเร็กทอรีย่อย Pytest จะระบุไฟล์เหล่านั้นโดยอัตโนมัติว่าเป็นไฟล์ทดสอบ เราcan ทำให้ pytest เรียกใช้ชื่อไฟล์อื่นโดยกล่าวถึงอย่างชัดเจน

Pytest ต้องการให้ชื่อฟังก์ชันทดสอบขึ้นต้นด้วย test. ชื่อฟังก์ชันที่ไม่ใช่รูปแบบtest*ไม่ถือว่าเป็นฟังก์ชันทดสอบโดย pytest เราcannot ทำให้ pytest พิจารณาฟังก์ชันใด ๆ ที่ไม่ได้ขึ้นต้นด้วย test เป็นฟังก์ชันทดสอบ

เราจะเข้าใจการดำเนินการทดสอบในบทต่อ ๆ ไปของเรา

ตอนนี้เราจะเริ่มต้นด้วยโปรแกรม pytest แรกของเรา ก่อนอื่นเราจะสร้างไดเร็กทอรีจากนั้นสร้างไฟล์ทดสอบของเราในไดเร็กทอรี

ให้เราทำตามขั้นตอนที่แสดงด้านล่าง -

  • สร้างไดเร็กทอรีใหม่ชื่อ automation และไปที่ไดเร็กทอรีในบรรทัดคำสั่งของคุณ

  • สร้างไฟล์ชื่อ test_square.py และเพิ่มรหัสด้านล่างลงในไฟล์นั้น

import math

def test_sqrt():
   num = 25
   assert math.sqrt(num) == 5

def testsquare():
   num = 7
   assert 7*7 == 40

def tesequality():
   assert 10 == 11

ทำการทดสอบโดยใช้คำสั่งต่อไปนี้ -

pytest

คำสั่งดังกล่าวจะสร้างผลลัพธ์ต่อไปนี้ -

test_square.py .F
============================================== FAILURES 
==============================================
______________________________________________ testsquare 
_____________________________________________
   def testsquare():
   num=7
>  assert 7*7 == 40
E  assert (7 * 7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.06 seconds 
=================================

ดูบรรทัดแรกของผลลัพธ์ จะแสดงชื่อไฟล์และผลลัพธ์ F หมายถึงความล้มเหลวในการทดสอบและจุด (.) แสดงถึงความสำเร็จในการทดสอบ

ด้านล่างนี้เราสามารถดูรายละเอียดของการทดสอบที่ล้มเหลว จะแสดงข้อความที่การทดสอบล้มเหลว ในตัวอย่างของเรา 7 * 7 ถูกเปรียบเทียบเพื่อความเท่าเทียมกับ 40 ซึ่งไม่ถูกต้อง ในท้ายที่สุดเราจะเห็นสรุปการดำเนินการทดสอบ 1 ล้มเหลวและ 1 ผ่าน

ฟังก์ชัน tesequality จะไม่ถูกเรียกใช้เนื่องจาก pytest จะไม่ถือว่าเป็นการทดสอบเนื่องจากชื่อของมันไม่ใช่รูปแบบ test*.

ตอนนี้ดำเนินการคำสั่งด้านล่างและดูผลลัพธ์อีกครั้ง -

pytest -v

-v เพิ่มความฟุ่มเฟื่อย

test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
============================================== FAILURES 
==============================================
_____________________________________________ testsquare 
_____________________________________________
   def testsquare():
   num = 7
>  assert 7*7 == 40
E  assert (7 * 7) == 40
test_square.py:9: AssertionError
================================= 1 failed, 1 passed in 0.04 seconds 
=================================

ตอนนี้ผลลัพธ์อธิบายได้มากขึ้นเกี่ยวกับการทดสอบที่ล้มเหลวและการทดสอบที่ผ่าน

Note - คำสั่ง pytest จะเรียกใช้ไฟล์รูปแบบทั้งหมด test_* หรือ *_test ในไดเร็กทอรีปัจจุบันและไดเร็กทอรีย่อย

ในบทนี้เราจะเรียนรู้วิธีเรียกใช้ไฟล์ทดสอบไฟล์เดียวและไฟล์ทดสอบหลายไฟล์ เรามีไฟล์ทดสอบแล้วtest_square.pyสร้างขึ้น สร้างไฟล์ทดสอบใหม่test_compare.py ด้วยรหัสต่อไปนี้ -

def test_greater():
   num = 100
   assert num > 100

def test_greater_equal():
   num = 100
   assert num >= 100

def test_less():
   num = 100
   assert num < 200

ตอนนี้เพื่อเรียกใช้การทดสอบทั้งหมดจากไฟล์ทั้งหมด (2 ไฟล์ที่นี่) เราต้องเรียกใช้คำสั่งต่อไปนี้ -

pytest -v

คำสั่งดังกล่าวจะเรียกใช้การทดสอบจากทั้งสองอย่าง test_square.py และ test_compare.py. ผลลัพธ์จะถูกสร้างขึ้นดังนี้ -

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
test_square.py::test_sqrt PASSED
test_square.py::testsquare FAILED
================================================ FAILURES 
================================================
______________________________________________ test_greater 
______________________________________________
   def test_greater():
   num = 100
>  assert num > 100
E  assert 100 > 100

test_compare.py:3: AssertionError
_______________________________________________ testsquare 
_______________________________________________
   def testsquare():
   num = 7
>  assert 7*7 == 40
E  assert (7 * 7) == 40

test_square.py:9: AssertionError
=================================== 2 failed, 3 passed in 0.07 seconds 
===================================

ในการดำเนินการทดสอบจากไฟล์เฉพาะให้ใช้ไวยากรณ์ต่อไปนี้ -

pytest <filename> -v

ตอนนี้เรียกใช้คำสั่งต่อไปนี้ -

pytest test_compare.py -v

คำสั่งดังกล่าวจะดำเนินการทดสอบจากไฟล์เท่านั้น test_compare.py. ผลลัพธ์ของเราจะเป็น -

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
test_compare.py::test_less PASSED
============================================== FAILURES 
==============================================
____________________________________________ test_greater 
____________________________________________
   def test_greater():
   num = 100
>  assert num > 100
E  assert 100 > 100
test_compare.py:3: AssertionError
================================= 1 failed, 2 passed in 0.04 seconds 
=================================

ในสถานการณ์จริงเราจะมีไฟล์ทดสอบหลายไฟล์และแต่ละไฟล์จะมีการทดสอบจำนวนหนึ่ง การทดสอบจะครอบคลุมโมดูลและฟังก์ชันต่างๆ สมมติว่าเราต้องการเรียกใช้การทดสอบเฉพาะชุดหนึ่ง เราจะไปต่อได้อย่างไร

Pytest มีสองวิธีในการเรียกใช้ชุดย่อยของชุดทดสอบ

  • เลือกการทดสอบที่จะเรียกใช้ตามการจับคู่สตริงย่อยของชื่อการทดสอบ
  • เลือกกลุ่มการทดสอบที่จะเรียกใช้ตามเครื่องหมายที่ใช้

เราจะอธิบายสองสิ่งนี้พร้อมตัวอย่างในบทต่อ ๆ ไป

ในการดำเนินการทดสอบที่มีสตริงในชื่อเราสามารถใช้ไวยากรณ์ต่อไปนี้ -

pytest -k <substring> -v

-k <substring> แทนสตริงย่อยที่จะค้นหาในชื่อการทดสอบ

ตอนนี้เรียกใช้คำสั่งต่อไปนี้ -

pytest -k great -v

การดำเนินการนี้จะเรียกใช้ชื่อการทดสอบทั้งหมดที่มีคำ ‘great’ในชื่อของมัน ในกรณีนี้คือtest_greater() และ test_greater_equal(). ดูผลลัพธ์ด้านล่าง

test_compare.py::test_greater FAILED
test_compare.py::test_greater_equal PASSED
============================================== FAILURES 
==============================================
____________________________________________ test_greater 
____________________________________________
def test_greater():
num = 100
>  assert num > 100
E  assert 100 > 100
test_compare.py:3: AssertionError
========================== 1 failed, 1 passed, 3 deselected in 0.07 seconds 
==========================

ในผลลัพธ์นี้เราจะเห็นการทดสอบ 3 รายการที่ยกเลิกการเลือก เนื่องจากชื่อการทดสอบเหล่านั้นไม่มีคำว่าgreat ในพวกเขา

Note - ชื่อของฟังก์ชันการทดสอบควรยังคงขึ้นต้นด้วย 'test'

ในบทนี้เราจะเรียนรู้วิธีจัดกลุ่มการทดสอบโดยใช้เครื่องหมาย

Pytest อนุญาตให้เราใช้เครื่องหมายในฟังก์ชันทดสอบ เครื่องหมายใช้เพื่อตั้งค่าคุณสมบัติ / คุณลักษณะต่างๆเพื่อทดสอบฟังก์ชัน Pytest มีเครื่องหมาย inbuilt จำนวนมากเช่น xfail, skip และ parametrize นอกเหนือจากนั้นผู้ใช้สามารถสร้างชื่อเครื่องหมายของตนเองได้ เครื่องหมายถูกนำไปใช้กับการทดสอบโดยใช้ไวยากรณ์ที่ระบุด้านล่าง -

@pytest.mark.<markername>

ในการใช้เครื่องหมายเราต้อง import pytestโมดูลในไฟล์ทดสอบ เราสามารถกำหนดชื่อเครื่องหมายของเราเองในการทดสอบและเรียกใช้การทดสอบด้วยชื่อเครื่องหมายเหล่านั้น

ในการเรียกใช้การทดสอบที่ทำเครื่องหมายไว้เราสามารถใช้ไวยากรณ์ต่อไปนี้ -

pytest -m <markername> -v

-m <markername> แสดงถึงชื่อเครื่องหมายของการทดสอบที่จะดำเนินการ

อัปเดตไฟล์ทดสอบของเรา test_compare.py และ test_square.pyด้วยรหัสต่อไปนี้ เรากำลังกำหนด 3 เครื่องหมาย– great, square, others.

test_compare.py

import pytest
@pytest.mark.great
def test_greater():
   num = 100
   assert num > 100

@pytest.mark.great
def test_greater_equal():
   num = 100
   assert num >= 100

@pytest.mark.others
def test_less():
   num = 100
   assert num < 200

test_square.py

import pytest
import math

@pytest.mark.square
def test_sqrt():
   num = 25
   assert math.sqrt(num) == 5

@pytest.mark.square
def testsquare():
   num = 7
   assert 7*7 == 40

@pytest.mark.others
   def test_equality():
   assert 10 == 11

ตอนนี้เพื่อเรียกใช้การทดสอบที่ทำเครื่องหมายเป็น othersเรียกใช้คำสั่งต่อไปนี้ -

pytest -m others -v

ดูผลลัพธ์ด้านล่าง ดำเนินการทดสอบ 2 รายการที่ทำเครื่องหมายว่าothers.

test_compare.py::test_less PASSED
test_square.py::test_equality FAILED
============================================== FAILURES
==============================================
___________________________________________ test_equality
____________________________________________
   @pytest.mark.others
   def test_equality():
>  assert 10 == 11
E  assert 10 == 11
test_square.py:16: AssertionError
========================== 1 failed, 1 passed, 4 deselected in 0.08 seconds
==========================

ในทำนองเดียวกันเราสามารถเรียกใช้การทดสอบกับเครื่องหมายอื่น ๆ ได้เช่นกัน - เยี่ยมมากเปรียบเทียบได้

ส่วนควบเป็นฟังก์ชันซึ่งจะทำงานก่อนการทดสอบแต่ละฟังก์ชันที่จะใช้ การแข่งขันใช้เพื่อป้อนข้อมูลบางส่วนไปยังการทดสอบเช่นการเชื่อมต่อฐานข้อมูล URL ที่จะทดสอบและข้อมูลอินพุตบางประเภท ดังนั้นแทนที่จะเรียกใช้รหัสเดียวกันสำหรับการทดสอบทุกครั้งเราสามารถแนบฟังก์ชันฟิกซ์เจอร์เข้ากับการทดสอบและจะเรียกใช้และส่งคืนข้อมูลไปยังการทดสอบก่อนดำเนินการทดสอบแต่ละครั้ง

ฟังก์ชันถูกทำเครื่องหมายว่าเป็นฟิกซ์เจอร์โดย -

@pytest.fixture

ฟังก์ชันทดสอบสามารถใช้ฟิกซ์เจอร์ได้โดยระบุชื่อฟิกซ์เจอร์เป็นพารามิเตอร์อินพุต

สร้างไฟล์ test_div_by_3_6.py และเพิ่มรหัสด้านล่างลงไป

import pytest

@pytest.fixture
def input_value():
   input = 39
   return input

def test_divisible_by_3(input_value):
   assert input_value % 3 == 0

def test_divisible_by_6(input_value):
   assert input_value % 6 == 0

ที่นี่เรามีฟังก์ชันติดตั้งชื่อ input_valueซึ่งให้ข้อมูลเข้าในการทดสอบ ในการเข้าถึงฟังก์ชันฟิกซ์เจอร์การทดสอบต้องระบุชื่อฟิกซ์เจอร์เป็นพารามิเตอร์อินพุต

Pytest ในขณะที่กำลังดำเนินการทดสอบจะเห็นชื่อฟิกซ์เจอร์เป็นพารามิเตอร์อินพุต จากนั้นเรียกใช้ฟังก์ชันฟิกซ์เจอร์และค่าที่ส่งคืนจะถูกเก็บไว้ในพารามิเตอร์อินพุตซึ่งสามารถใช้โดยการทดสอบได้

ดำเนินการทดสอบโดยใช้คำสั่งต่อไปนี้ -

pytest -k divisible -v

คำสั่งดังกล่าวจะสร้างผลลัพธ์ต่อไปนี้ -

test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
   def test_divisible_by_6(input_value):
>  assert input_value % 6 == 0
E  assert (39 % 6) == 0
test_div_by_3_6.py:12: AssertionError
========================== 1 failed, 1 passed, 6 deselected in 0.07 seconds
==========================

อย่างไรก็ตามแนวทางดังกล่าวมาพร้อมกับข้อ จำกัด ของตัวเอง ฟังก์ชันฟิกซ์เจอร์ที่กำหนดไว้ภายในไฟล์ทดสอบมีขอบเขตภายในไฟล์ทดสอบเท่านั้น เราไม่สามารถใช้ฟิกซ์เจอร์นั้นในไฟล์ทดสอบอื่นได้ ในการทำให้ฟิกซ์เจอร์พร้อมใช้งานกับไฟล์ทดสอบหลายไฟล์เราต้องกำหนดฟังก์ชันฟิกซ์เจอร์ในไฟล์ที่เรียกว่า conftest.pyconftest.py จะอธิบายในบทถัดไป

เราสามารถกำหนดฟังก์ชันฟิกซ์เจอร์ในไฟล์นี้เพื่อให้เข้าถึงได้จากไฟล์ทดสอบหลายไฟล์

สร้างไฟล์ใหม่ conftest.py และเพิ่มรหัสด้านล่างเข้าไป -

import pytest

@pytest.fixture
def input_value():
   input = 39
   return input

แก้ไขไฟล์ test_div_by_3_6.py เพื่อลบฟังก์ชันการติดตั้ง -

import pytest

def test_divisible_by_3(input_value):
   assert input_value % 3 == 0

def test_divisible_by_6(input_value):
   assert input_value % 6 == 0

สร้างไฟล์ใหม่ test_div_by_13.py -

import pytest

def test_divisible_by_13(input_value):
   assert input_value % 13 == 0

ตอนนี้เรามีไฟล์ test_div_by_3_6.py และ test_div_by_13.py ใช้ประโยชน์จากฟิกซ์เจอร์ที่กำหนดไว้ใน conftest.py.

เรียกใช้การทดสอบโดยดำเนินการคำสั่งต่อไปนี้ -

pytest -k divisible -v

คำสั่งดังกล่าวจะสร้างผลลัพธ์ต่อไปนี้ -

test_div_by_13.py::test_divisible_by_13 PASSED
test_div_by_3_6.py::test_divisible_by_3 PASSED
test_div_by_3_6.py::test_divisible_by_6 FAILED
============================================== FAILURES
==============================================
________________________________________ test_divisible_by_6
_________________________________________
input_value = 39
   def test_divisible_by_6(input_value):
>  assert input_value % 6 == 0
E  assert (39 % 6) == 0
test_div_by_3_6.py:7: AssertionError
========================== 1 failed, 2 passed, 6 deselected in 0.09 seconds
==========================

การทดสอบจะค้นหาฟิกซ์เจอร์ในไฟล์เดียวกัน เนื่องจากไม่พบฟิกซ์เจอร์ในไฟล์มันจะตรวจสอบฟิกซ์เจอร์ในไฟล์ conftest.py ในการค้นหาวิธีการติดตั้งจะถูกเรียกใช้และผลลัพธ์จะถูกส่งกลับไปยังอาร์กิวเมนต์อินพุตของการทดสอบ

การกำหนดพารามิเตอร์ของการทดสอบทำขึ้นเพื่อรันการทดสอบกับอินพุตหลายชุด เราสามารถทำได้โดยใช้เครื่องหมายต่อไปนี้ -

@pytest.mark.parametrize

คัดลอกโค้ดด้านล่างลงในไฟล์ที่เรียกว่า test_multiplication.py -

import pytest

@pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
def test_multiplication_11(num, output):
   assert 11*num == output

ที่นี่การทดสอบจะคูณอินพุตด้วย 11 และเปรียบเทียบผลลัพธ์กับผลลัพธ์ที่คาดหวัง การทดสอบมีอินพุต 4 ชุดแต่ละชุดมี 2 ค่า - หนึ่งคือจำนวนที่จะคูณด้วย 11 และอีกชุดคือผลลัพธ์ที่คาดหวัง

ดำเนินการทดสอบโดยรันคำสั่งต่อไปนี้ -

Pytest -k multiplication -v

คำสั่งดังกล่าวจะสร้างผลลัพธ์ต่อไปนี้ -

test_multiplication.py::test_multiplication_11[1-11] PASSED
test_multiplication.py::test_multiplication_11[2-22] PASSED
test_multiplication.py::test_multiplication_11[3-35] FAILED
test_multiplication.py::test_multiplication_11[4-44] PASSED
============================================== FAILURES
==============================================
_________________ test_multiplication_11[3-35] __________________
num = 3, output = 35
   @pytest.mark.parametrize("num, output",[(1,11),(2,22),(3,35),(4,44)])
   def test_multiplication_11(num, output):
>  assert 11*num == output
E  assert (11 * 3) == 35
test_multiplication.py:5: AssertionError
============================== 1 failed, 3 passed, 8 deselected in 0.08 seconds
==============================

ในบทนี้เราจะเรียนรู้เกี่ยวกับการทดสอบ Skip และ Xfail ใน Pytest

ตอนนี้พิจารณาสถานการณ์ด้านล่าง -

  • การทดสอบไม่เกี่ยวข้องในบางครั้งเนื่องจากสาเหตุบางประการ
  • กำลังมีการใช้งานคุณลักษณะใหม่และเราได้เพิ่มการทดสอบสำหรับคุณลักษณะนั้นแล้ว

ในสถานการณ์เหล่านี้เรามีตัวเลือกในการ xfail การทดสอบหรือข้ามการทดสอบ

Pytest จะดำเนินการทดสอบ xfailed แต่จะไม่ถือว่าเป็นส่วนที่ล้มเหลวหรือผ่านการทดสอบ รายละเอียดของการทดสอบเหล่านี้จะไม่ถูกพิมพ์แม้ว่าการทดสอบจะล้มเหลวก็ตาม (โปรดจำไว้ว่า pytest มักจะพิมพ์รายละเอียดการทดสอบที่ล้มเหลว) เราสามารถ xfail การทดสอบโดยใช้เครื่องหมายต่อไปนี้ -

@pytest.mark.xfail

การข้ามการทดสอบหมายความว่าการทดสอบจะไม่ถูกดำเนินการ เราสามารถข้ามการทดสอบโดยใช้เครื่องหมายต่อไปนี้ -

@pytest.mark.skip

หลังจากนั้นเมื่อการทดสอบมีความเกี่ยวข้องเราสามารถลบเครื่องหมายออกได้

แก้ไขไฟล์ test_compare.py เราต้องรวมเครื่องหมาย xfail และข้ามไว้แล้ว -

import pytest
@pytest.mark.xfail
@pytest.mark.great
def test_greater():
   num = 100
   assert num > 100

@pytest.mark.xfail
@pytest.mark.great
def test_greater_equal():
   num = 100
   assert num >= 100

@pytest.mark.skip
@pytest.mark.others
def test_less():
   num = 100
   assert num < 200

ดำเนินการทดสอบโดยใช้คำสั่งต่อไปนี้ -

pytest test_compare.py -v

เมื่อดำเนินการคำสั่งดังกล่าวจะสร้างผลลัพธ์ต่อไปนี้ -

test_compare.py::test_greater xfail
test_compare.py::test_greater_equal XPASS
test_compare.py::test_less SKIPPED
============================ 1 skipped, 1 xfailed, 1 xpassed in 0.06 seconds
============================

ในสถานการณ์จริงเมื่อโค้ดเวอร์ชันใหม่พร้อมใช้งานแล้วโค้ดจะถูกปรับใช้ในสภาพแวดล้อมแบบ pre-prod / staging ก่อน จากนั้นชุดทดสอบจะทำงาน

รหัสนี้มีคุณสมบัติสำหรับการปรับใช้กับการใช้งานจริงเมื่อชุดทดสอบผ่าน หากมีความล้มเหลวในการทดสอบไม่ว่าจะเป็นรหัสเดียวหรือหลายรหัสยังไม่พร้อมใช้งานจริง

ดังนั้นจะเกิดอะไรขึ้นถ้าเราต้องการหยุดการทำงานของชุดทดสอบในไม่ช้าหลังจาก n จำนวนการทดสอบล้มเหลว สามารถทำได้ใน pytest โดยใช้ maxfail

ไวยากรณ์เพื่อหยุดการทำงานของชุดทดสอบในไม่ช้าหลังจาก n จำนวนการทดสอบล้มเหลวมีดังนี้ -

pytest --maxfail = <num>

สร้างไฟล์ test_failure.py ด้วยรหัสต่อไปนี้

import pytest
import math

def test_sqrt_failure():
   num = 25
   assert math.sqrt(num) == 6

def test_square_failure():
   num = 7
   assert 7*7 == 40

def test_equality_failure():
   assert 10 == 11

การทดสอบทั้ง 3 ครั้งจะล้มเหลวในการเรียกใช้ไฟล์ทดสอบนี้ ที่นี่เราจะหยุดการดำเนินการทดสอบหลังจากความล้มเหลวหนึ่งครั้งโดย -

pytest test_failure.py -v --maxfail = 1
test_failure.py::test_sqrt_failure FAILED
=================================== FAILURES
=================================== _______________________________________
test_sqrt_failure __________________________________________
   def test_sqrt_failure():
   num = 25
>  assert math.sqrt(num) == 6
E  assert 5.0 == 6
E  + where 5.0 = <built-in function sqrt>(25)
E  + where <built-in function sqrt>= math.sqrt
test_failure.py:6: AssertionError
=============================== 1 failed in 0.04 seconds
===============================

จากผลลัพธ์ข้างต้นเราจะเห็นการดำเนินการหยุดลงในความล้มเหลวครั้งเดียว

โดยค่าเริ่มต้น pytest จะรันการทดสอบตามลำดับ ในสถานการณ์จริงชุดทดสอบจะมีไฟล์ทดสอบจำนวนหนึ่งและแต่ละไฟล์จะมีการทดสอบมากมาย ซึ่งจะนำไปสู่การดำเนินการครั้งใหญ่ เพื่อเอาชนะสิ่งนี้ pytest มีตัวเลือกให้เราทำการทดสอบควบคู่กันไป

สำหรับสิ่งนี้เราต้องติดตั้งปลั๊กอิน pytest-xdist ก่อน

ติดตั้ง pytest-xdist โดยรันคำสั่งต่อไปนี้ -

pip install pytest-xdist

ตอนนี้เราสามารถเรียกใช้การทดสอบโดยใช้ไวยากรณ์ pytest -n <num>

pytest -n 3

-n <num> รันการทดสอบโดยใช้คนงานหลายคนนี่คือ 3

เราจะไม่มีความแตกต่างของเวลามากนักเมื่อมีการทดสอบเพียงเล็กน้อยเท่านั้น อย่างไรก็ตามจะมีความสำคัญเมื่อชุดทดสอบมีขนาดใหญ่

เราสามารถสร้างรายละเอียดของการดำเนินการทดสอบในไฟล์ xml ไฟล์ xml นี้มีประโยชน์เป็นหลักในกรณีที่เรามีแดชบอร์ดที่แสดงผลการทดสอบ ในกรณีเช่นนี้สามารถแยกวิเคราะห์ xml เพื่อดูรายละเอียดของการดำเนินการได้

ตอนนี้เราจะดำเนินการทดสอบจาก test_multiplcation.py และสร้าง xml โดยเรียกใช้

pytest test_multiplication.py -v --junitxml="result.xml"

ตอนนี้เราสามารถเห็น result.xml ถูกสร้างขึ้นด้วยข้อมูลต่อไปนี้ -

<?xml version = "1.0" encoding = "utf-8"?>
<testsuite errors = "0" failures = "1"
name = "pytest" skips = "0" tests = "4" time = "0.061">
   <testcase classname = "test_multiplication"          
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[1-11]"
      time = "0.00117516517639>
   </testcase>
   
   <testcase classname = "test_multiplication"    
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[2-22]"
      time = "0.00155973434448">
   </testcase>

   <testcase classname = "test_multiplication" 
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[3-35]" time = "0.00144290924072">
      failure message = "assert (11 * 3) == 35">num = 3, output = 35

         @pytest.mark.parametrize("num,
         output",[(1,11),(2,22),(3,35),(4,44)])
            
         def test_multiplication_11(num, output):> 
         assert 11*num == output
         E assert (11 * 3) == 35

         test_multiplication.py:5: AssertionErro
      </failure>
   </testcase>
   <testcase classname = "test_multiplication" 
      file = "test_multiplication.py"
      line = "2" name = "test_multiplication_11[4-44]"
      time = "0.000945091247559">
   </testcase>
</testsuite>

ที่นี่แท็ก <testsuit> สรุปมีการทดสอบ 4 ครั้งและจำนวนข้อผิดพลาดคือ 1

  • แท็ก <testcase> ให้รายละเอียดของการทดสอบที่ดำเนินการแต่ละครั้ง

  • แท็ก <failure> ให้รายละเอียดของรหัสทดสอบที่ล้มเหลว

ในบทช่วยสอน pytest นี้เราได้กล่าวถึงประเด็นต่อไปนี้ -

  • กำลังติดตั้ง pytest ..
  • การระบุไฟล์ทดสอบและฟังก์ชันการทดสอบ
  • การเรียกใช้ไฟล์ทดสอบทั้งหมดโดยใช้ pytest –v
  • การเรียกใช้ไฟล์เฉพาะ usimng pytest <filename> -v.
  • ดำเนินการทดสอบโดยสตริงย่อยที่ตรงกับ pytest -k <substring> -v
  • ดำเนินการทดสอบตามเครื่องหมาย pytest -m <marker_name> -v
  • การสร้างการแข่งขันโดยใช้ @ pytest.fixture
  • conftest.py อนุญาตให้เข้าถึงส่วนควบจากไฟล์หลายไฟล์
  • การทดสอบ Parametrizing โดยใช้ @ pytest.mark.parametrize
  • Xfailing การทดสอบโดยใช้ @ pytest.mark.xfail
  • ข้ามการทดสอบโดยใช้ @ pytest.mark.skip
  • หยุดการดำเนินการทดสอบกับ n ความล้มเหลวโดยใช้ pytest --maxfail = <num>
  • รันการทดสอบแบบขนานโดยใช้ pytest -n <num>
  • การสร้างผลลัพธ์ xml โดยใช้ pytest -v --junitxml = "result.xml"

บทช่วยสอนนี้แนะนำให้คุณรู้จักกับ pytest framework ตอนนี้คุณควรจะเริ่มเขียนแบบทดสอบโดยใช้ pytest ได้แล้ว

เป็นแนวทางปฏิบัติที่ดี -

  • สร้างไฟล์ทดสอบต่างๆตามฟังก์ชันการทำงาน / โมดูลที่กำลังทดสอบ
  • ตั้งชื่อที่มีความหมายเพื่อทดสอบไฟล์และวิธีการ
  • มีเครื่องหมายเพียงพอที่จะจัดกลุ่มการทดสอบตามเกณฑ์ต่างๆ
  • ใช้อุปกรณ์ติดตั้งเมื่อจำเป็น