ทดสอบคลาสและวิธีการ

เสร็จสมบูรณ์เมื่อ

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

เช่นเดียวกับฟังก์ชัน คุณยังสามารถเขียนการยืนยันโดยใช้คําสั่ง assert ได้

สร้างคลาสทดสอบ

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

นี่คือลักษณะที่ปรากฏของฟังก์ชัน:

import os

def is_done(path):
    if not os.path.exists(path):
        return False
    with open(path) as _f:
        contents = _f.read()
    if "yes" in contents.lower():
        return True
    elif "no" in contents.lower():
        return False

ในตอนนี้ นี่คือลักษณะคลาสที่มีการทดสอบสองรายการ (หนึ่งรายการสําหรับแต่ละเงื่อนไข) ในไฟล์ที่มีชื่อว่า test_files.py มีลักษณะดังนี้:

class TestIsDone:

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

ความระมัดระวัง

วิธีทดสอบใช้เส้นทาง /tmp สําหรับไฟล์ทดสอบชั่วคราวเนื่องจากง่ายต่อการใช้สําหรับตัวอย่าง อย่างไรก็ตาม ถ้าคุณจําเป็นต้องใช้ไฟล์ชั่วคราว พิจารณาการใช้ไลบรารี เช่น tempfile ที่สามารถสร้าง (และลบ) ไฟล์เหล่านั้นได้อย่างปลอดภัย ไม่ใช่ทุกระบบที่มีไดเรกทอรี /tmp และตําแหน่งที่ตั้งอาจไม่ชั่วคราวทั้งนี้ขึ้นอยู่กับระบบปฏิบัติการ

เรียกใช้การทดสอบด้วยค่าสถานะ -v เพื่อเพิ่มความละเอียดแสดงการทดสอบที่ส่งผ่าน:

pytest -v test_files.py
============================= test session starts ==============================
Python 3.9.6, pytest-6.2.5, py-1.11.0, pluggy-1.0.0 
cachedir: .pytest_cache
rootdir: /private/
collected 2 items

test_files.py::TestIsDone::test_yes PASSED                               [ 50%]
test_files.py::TestIsDone::test_no PASSED                                [100%]

============================== 2 passed in 0.00s ===============================

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

วิธีการของตัวช่วยเหลือ

ในคลาสการทดสอบ มีสองสามวิธีที่คุณสามารถใช้ในการตั้งค่าและทําให้การดําเนินการทดสอบแย่ลง Pytest ดําเนินการโดยอัตโนมัติหากกําหนดไว้ หากต้องการใช้วิธีการเหล่านี้ คุณควรทราบว่าวิธีการดังกล่าวมีลําดับและลักษณะการทํางานที่เฉพาะเจาะจง

  • setup: ดําเนินการหนึ่งครั้งก่อนการทดสอบแต่ละครั้งในคลาส
  • teardown: ดําเนินการหนึ่งครั้งหลังจากการทดสอบแต่ละครั้งในคลาส
  • setup_class: ดําเนินการหนึ่งครั้งก่อนการทดสอบทั้งหมดในคลาส
  • teardown_class: ดําเนินการหนึ่งครั้งหลังจากการทดสอบทั้งหมดในคลาส

เมื่อการทดสอบจําเป็นต้องใช้ทรัพยากรที่คล้ายกัน (หรือเหมือนกัน) ในการทํางาน จะมีประโยชน์ในการเขียนวิธีการตั้งค่า ตามแนวคิดแล้ว การทดสอบไม่ควรทิ้งทรัพยากรไว้เมื่อเสร็จสมบูรณ์ ดังนั้นวิธีการฉีกขาดสามารถช่วยในการทดสอบการล้างข้อมูลในสถานการณ์เหล่านั้นได้

ล้าง

มาดูคลาสการทดสอบที่อัปเดตแล้วที่ล้างไฟล์หลังจากการทดสอบแต่ละครั้ง:

class TestIsDone:

    def teardown(self):
        if os.path.exists("/tmp/test_file"):
            os.remove("/tmp/test_file")

    def test_yes(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("yes")
        assert is_done("/tmp/test_file") is True

    def test_no(self):
        with open("/tmp/test_file", "w") as _f:
            _f.write("no")
        assert is_done("/tmp/test_file") is False

เนื่องจากเราใช้วิธี teardown() คลาสการทดสอบนี้จะไม่ทิ้ง /tmp/test_file ไว้ข้างหลังอีกต่อไป

ตั้ง ค่า

การปรับปรุงอีกประการหนึ่งที่เราสามารถทํากับคลาสนี้คือการเพิ่มตัวแปรที่ชี้ไปยังไฟล์ เนื่องจากไฟล์ได้รับการประกาศในหกที่แล้ว การเปลี่ยนแปลงใด ๆ ในเส้นทางจะหมายถึงการเปลี่ยนแปลงในทุกจุดเหล่านั้น ตัวอย่างนี้แสดงให้เห็นว่าคลาสมีลักษณะอย่างไรด้วยวิธีการ setup() ที่เพิ่มที่ตรวจนับตัวแปรเส้นทาง:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def test_yes(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        with open(self.tmp_file, "w") as _f:
            _f.write("no")
        assert is_done(self.tmp_file) is False

วิธีการของตัวช่วยเหลือแบบกําหนดเอง

คุณสามารถสร้างวิธีการของตัวช่วยเหลือแบบกําหนดเองในคลาส วิธีการเหล่านี้ต้องไม่มีคํานําหน้าด้วยชื่อ test และไม่สามารถตั้งชื่อเป็นวิธีการตั้งค่าหรือการล้างข้อมูลได้ ใน TestIsDone คลาส เราสามารถสร้างไฟล์ชั่วคราวในตัวช่วยเหลือแบบกําหนดเองโดยอัตโนมัติ วิธีการของตัวช่วยเหลือแบบกําหนดเองอาจมีลักษณะดังตัวอย่างนี้:

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

Pytest ไม่ได้ดําเนินการวิธีการ write_tmp_file() โดยอัตโนมัติ และวิธีอื่น ๆ สามารถเรียกใช้โดยตรงเพื่อบันทึกงานที่ซ้ํา ๆ เช่น การเขียนไปยังไฟล์

คลาสทั้งหมดมีลักษณะดังนี้หลังจากอัปเดตวิธีทดสอบเพื่อใช้ตัวช่วยเหลือแบบกําหนดเอง:

class TestIsDone:

    def setup(self):
        self.tmp_file = "/tmp/test_file"

    def teardown(self):
        if os.path.exists(self.tmp_file):
            os.remove(self.tmp_file)

    def write_tmp_file(self, content):
        with open(self.tmp_file, "w") as _f:
            _f.write(content)

    def test_yes(self):
        self.write_tmp_file("yes")
        assert is_done(self.tmp_file) is True

    def test_no(self):
        self.write_tmp_file("no")
        assert is_done(self.tmp_file) is False

เมื่อต้องการใช้คลาสแทนฟังก์ชัน

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

  • การทดสอบของคุณจําเป็นต้องมีรหัสผู้ช่วยเหลือในการตั้งค่าหรือการล้างข้อมูลที่คล้ายกันหรือไม่
  • การจัดกลุ่มการทดสอบของคุณเข้าด้วยกันสมเหตุสมผลหรือไม่
  • มีการทดสอบอย่างน้อย 2-3 ครั้งในชุดการทดสอบของคุณหรือไม่
  • การทดสอบของคุณสามารถใช้ประโยชน์จากชุดฟังก์ชันผู้ช่วยเหลือทั่วไปได้หรือไม่