การบันทึกภายในการทดสอบ pytest


94

ฉันต้องการใส่ข้อความบันทึกในฟังก์ชันทดสอบเพื่อตรวจสอบตัวแปรสถานะบางอย่าง

ฉันมีข้อมูลโค้ดต่อไปนี้:

import pytest,os
import logging

logging.basicConfig(level=logging.DEBUG)
mylogger = logging.getLogger()

#############################################################################

def setup_module(module):
    ''' Setup for the entire module '''
    mylogger.info('Inside Setup')
    # Do the actual setup stuff here
    pass

def setup_function(func):
    ''' Setup for test functions '''
    if func == test_one:
        mylogger.info(' Hurray !!')

def test_one():
    ''' Test One '''
    mylogger.info('Inside Test 1')
    #assert 0 == 1
    pass

def test_two():
    ''' Test Two '''
    mylogger.info('Inside Test 2')
    pass

if __name__ == '__main__':
    mylogger.info(' About to start the tests ')
    pytest.main(args=[os.path.abspath(__file__)])
    mylogger.info(' Done executing the tests ')

ฉันได้รับผลลัพธ์ต่อไปนี้:

[bmaryada-mbp:/Users/bmaryada/dev/platform/main/proto/tests/tpch $]python minitest.py
INFO:root: About to start the tests 
======================================================== test session starts =========================================================
platform darwin -- Python 2.6.2 -- pytest-2.0.0
collected 2 items 

minitest.py ..

====================================================== 2 passed in 0.01 seconds ======================================================
INFO:root: Done executing the tests 

สังเกตว่ามีเพียงข้อความบันทึกจาก'__name__ == __main__'บล็อกเท่านั้นที่ถูกส่งไปยังคอนโซล

มีวิธีบังคับpytestให้ส่งการบันทึกไปยังคอนโซลจากวิธีทดสอบด้วยหรือไม่?


3
คุณอาจดูคำตอบนี้ซึ่งโพสต์โดยผู้สร้างของ py.test เขาแนะนำปลั๊กอิน pytest ที่ให้ความเก่งกาจในระดับสูง
chb

คำตอบ:


30

ได้ผลสำหรับฉันนี่คือผลลัพธ์ที่ฉันได้รับ: [snip -> ตัวอย่างไม่ถูกต้อง]

แก้ไข: ดูเหมือนว่าคุณต้องส่ง-sตัวเลือกไปที่ py.test จึงจะไม่จับ stdout ที่นี่ (py.test ไม่ได้ติดตั้ง) python pytest.py -s pyt.pyมันก็เพียงพอที่จะใช้งาน

สำหรับรหัสของคุณทั้งหมดที่คุณต้องการที่จะผ่าน-sในargsการmain:

 pytest.main(args=['-s', os.path.abspath(__file__)])

ดูเอกสาร py.test ในการส่งออกจับ


ขออภัย. ฉันวางรหัสด้วยความเร่งรีบ โปรดลบ 'assert 0 == 1' ออกจากฟังก์ชัน 'test_one' เพื่อสังเกตเห็น 'ปัญหา' เฉพาะเมื่อมีความล้มเหลวบางอย่าง (ซึ่งฉันบังคับโดยการยืนยันเท็จ) py.test ดูเหมือนว่าจะพิมพ์ข้อมูลการบันทึก
superselector

ไม่มีปัญหาฉันพบวิธีแก้ไขในบรรทัดคำสั่งโดยมองหาวิธีที่เป็นโปรแกรม
TryPyPy

1
คุณยังสามารถเปลี่ยนเส้นทางเอาต์พุตการบันทึกไปยังไฟล์บางไฟล์แทนที่จะเป็น stderr โดยปริยายเริ่มต้น
hpk42

@superselector hpk42 เป็น py.test คนทำฟัง. IIUC logging.basicConfig(filename="somelog.txt", level=logging.DEBUG)ในรหัสของคุณก็ต้องการจะ
TryPyPy

128

ตั้งแต่เวอร์ชัน 3.3 pytestสนับสนุนการบันทึกแบบสดซึ่งหมายความว่าบันทึกทั้งหมดที่ปล่อยออกมาในการทดสอบจะถูกพิมพ์ไปยังเทอร์มินัลทันที คุณลักษณะนี้ได้รับการบันทึกไว้ในส่วนLive Logs การบันทึกสดถูกปิดใช้งานโดยค่าเริ่มต้น เพื่อเปิดใช้งานให้ตั้งค่าlog_cli = 1ในpyproject.toml1หรือpytest.ini2การตั้งค่า Live logging รองรับการส่งไปยังเทอร์มินัลและไฟล์ ตัวเลือกที่เกี่ยวข้องอนุญาตให้ปรับแต่งบันทึก:

ขั้ว:

  • log_cli_level
  • log_cli_format
  • log_cli_date_format

ไฟล์:

  • log_file
  • log_file_level
  • log_file_format
  • log_file_date_format

หมายเหตุ : log_cliธงไม่สามารถส่งผ่านจากบรรทัดคำสั่งและจะต้องpytest.iniมีการตั้งค่าใน ตัวเลือกอื่น ๆ ทั้งหมดสามารถส่งผ่านจากบรรทัดคำสั่งหรือตั้งค่าในไฟล์กำหนดค่า ตามที่KévinBarréชี้ไว้ในความคิดเห็นนี้การแทนที่ตัวเลือก ini จากบรรทัดคำสั่งสามารถทำได้ผ่านทาง-o/--overrideตัวเลือก ดังนั้นแทนที่จะประกาศlog_cliในpytest.iniคุณก็สามารถโทรติดต่อ:

$ pytest -o log_cli=true ...

ตัวอย่าง

ไฟล์ทดสอบอย่างง่ายที่ใช้สำหรับสาธิต:

# test_spam.py

import logging

LOGGER = logging.getLogger(__name__)


def test_eggs():
    LOGGER.info('eggs info')
    LOGGER.warning('eggs warning')
    LOGGER.error('eggs error')
    LOGGER.critical('eggs critical')
    assert True

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

การบันทึกสดไปยังเทอร์มินัลINFOระดับเอาต์พุตแฟนซี

การกำหนดค่าในpyproject.toml:

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "INFO"
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_cli_date_format = "%Y-%m-%d %H:%M:%S"

การกำหนดค่าที่เหมือนกันในระบบเดิมpytest.ini:

[pytest]
log_cli = 1
log_cli_level = INFO
log_cli_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_cli_date_format=%Y-%m-%d %H:%M:%S

ทำการทดสอบ:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
2018-08-01 14:33:20 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:33:20 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:33:20 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:33:20 [CRITICAL] eggs critical (test_spam.py:10)
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

บันทึกสดไปยังเทอร์มินัลและไฟล์เฉพาะข้อความและCRITICALระดับในเทอร์มินัลเอาต์พุตแฟนซีในpytest.logไฟล์

การกำหนดค่าในpyproject.toml:

[tool.pytest.ini_options]
log_cli = true
log_cli_level = "CRITICAL"
log_cli_format = "%(message)s"

log_file = "pytest.log"
log_file_level = "DEBUG"
log_file_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
log_file_date_format = "%Y-%m-%d %H:%M:%S"

การกำหนดค่าที่เหมือนกันในระบบเดิมpytest.ini:

[pytest]
log_cli = 1
log_cli_level = CRITICAL
log_cli_format = %(message)s

log_file = pytest.log
log_file_level = DEBUG
log_file_format = %(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)
log_file_date_format=%Y-%m-%d %H:%M:%S

ทดสอบการทำงาน:

$ pytest test_spam.py
=============================== test session starts ================================
platform darwin -- Python 3.6.4, pytest-3.7.0, py-1.5.3, pluggy-0.7.1 -- /Users/hoefling/.virtualenvs/stackoverflow/bin/python3.6
cachedir: .pytest_cache
rootdir: /Users/hoefling/projects/private/stackoverflow/so-4673373, inifile: pytest.ini
collected 1 item

test_spam.py::test_eggs
---------------------------------- live log call -----------------------------------
eggs critical
PASSED                                                                        [100%]

============================= 1 passed in 0.01 seconds =============================

$ cat pytest.log
2018-08-01 14:38:09 [    INFO] eggs info (test_spam.py:7)
2018-08-01 14:38:09 [ WARNING] eggs warning (test_spam.py:8)
2018-08-01 14:38:09 [   ERROR] eggs error (test_spam.py:9)
2018-08-01 14:38:09 [CRITICAL] eggs critical (test_spam.py:10)

1 pyproject.tomlรองรับตั้งแต่เวอร์ชัน 6.0 และเป็นตัวเลือกที่ดีที่สุด IMO ดูข้อกำหนดPEP 518

2แม้ว่าคุณยังสามารถกำหนดค่าpytestในsetup.cfgภายใต้[tool:pytest]ส่วนที่ไม่ได้ถูกล่อลวงไปทำอย่างนั้นเมื่อคุณต้องการที่จะให้รูปแบบการเข้าสู่ระบบการถ่ายทอดสดที่กำหนดเอง การอ่านเครื่องมืออื่น ๆsetup.cfgอาจใช้%(message)sกับการแก้ไขสตริงและล้มเหลว ทางเลือกที่ดีที่สุดคือการใช้pyproject.tomlอย่างไรก็ตามหากคุณถูกบังคับให้ใช้รูปแบบ ini-style เดิมให้ปฏิบัติตามpytest.iniเพื่อหลีกเลี่ยงข้อผิดพลาด


21
เกี่ยวกับโน้ตที่log_cliต้องอยู่ในpytest.iniดูเหมือนว่าคุณสามารถใช้-oตัวเลือกเพื่อแทนที่ค่าจากบรรทัดคำสั่ง pytest -o log_cli=true --log-cli-level=DEBUGเหมาะกับฉัน
KévinBarré

@ KévinBarréความคิดเห็นที่ดีมากและคำใบ้ที่เป็นประโยชน์โดยทั่วไปขอบคุณ! อัปเดตคำตอบ
hoefling

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

@CMCDragonkai น่าเสียดายที่pytestค่อนข้าง จำกัด ในเรื่องนั้น อย่างไรก็ตามสิ่งนี้ควรทำได้ด้วยการกำหนดค่าการบันทึกพิเศษสำหรับการทดสอบในแอปของคุณ ปิดการขยายพันธุ์ในตัวบันทึกของคุณและเพิ่ม "ตัวจัดการการทดสอบ" ที่บันทึกไปยังไฟล์ที่ระบุ ทางนี้,pytestจะบันทึกเฉพาะบันทึกที่มาจากการทดสอบในขณะที่ตัวจัดการแบบกำหนดเองจะดูแลเกี่ยวกับบันทึก SuT
hoefling

1
@OfekAgmon หากคุณต้องการจัดเก็บpytestเอาต์พุตคุณสามารถใช้--result-logอาร์กิวเมนต์ได้ (แม้ว่าจะทราบว่าเลิกใช้แล้วก็ตามนี่คือทางเลือกอื่น ) คุณไม่สามารถจัดเก็บpytestเอาต์พุตและเอาต์พุตการบันทึกแบบสดในไฟล์เดียวกันได้
hoefling
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.