Pytest framework combat--2--print--loguru--package

Pytest Tutorial

Strange phenomenon of print in Pytest framework

test_02_01.py

"""
pytest middle print usage of
"""
from assertpy import assert_that
import pytest


# fun1 is the function we test: pass a parameter automatically +1
def fun1(x):
    """
    If we accidentally write 1 to 0 when we develop.1
    :param x:
    :return:
    """
    return x + 0.1


def test_fun1():
    print('This is the failing use case,this print will print')
    assert_that(fun1(10)).is_equal_to(11)


def test_fun2():
    print('This is a successful use case,this print won't print')
    assert_that(fun1(10)).is_instance_of(float)

We execute in the terminal

pytest .\test_02_01.py

Output result:

PS D:\code\pytest_test\test_2_day> pytest .\test_02_01.py
============================================================ test session starts 
        print('This is the failing use case,this print will print')
>       assert_that(fun1(10)).is_equal_to(11)
E       AssertionError: Expected <10.1> to be equal to <11>, but was not.

test_02_01.py:20: AssertionError
----------------------------------------------------------- Captured stdout call -----------------------------------------
This is the failing use case,this print will print
========================================================== short test summary info =======================================
FAILED test_02_01.py::test_fun1 - AssertionError: Expected <10.1> to be equal to <11>, but was not.
======================================================== 1 failed, 1 passed in 0.14s =====================================
PS D:\code\pytest_test\test_2_day>

You can see ---- Captured stdout call --- The following is a failed use case, this print will print, but this is a successful use case, this print will not print

Here we need to note that test_fun1 is a failed use case and test_fun2 is a successful use case. So to summarize:

like,The execution result of the use case is Pass,in that use case print won't print
 like,The execution result of the use case is Fail,in that use case print will print out

What if I just want to print out all the prints?

We execute in the terminal:

pytest .\test_02_01.py -s

Output result:

PS D:\code\pytest_test\test_2_day> pytest .\test_02_01.py -s
============================================================ test session starts ==============================================
platform win32 -- Python 3.10.5, pytest-7.1.2, pluggy-1.0.0
rootdir: D:\code\pytest_test\test_2_day
collected 2 items                                                                                                                             

test_02_01.py This is the failing use case,this print will print
F This is a successful use case,this print won't print
.

================================================================= FAILURES ===================================================
_________________________________________________________________ test_fun1 ____________________________________________________

    def test_fun1():
        print('This is the failing use case,this print will print')
>       assert_that(fun1(10)).is_equal_to(11)
E       AssertionError: Expected <10.1> to be equal to <11>, but was not.

test_02_01.py:20: AssertionError
========================================================== short test summary info ============================================
FAILED test_02_01.py::test_fun1 - AssertionError: Expected <10.1> to be equal to <11>, but was not.
======================================================== 1 failed, 1 passed in 0.11s ==========================================
PS D:\code\pytest_test\test_2_day> 

In this way, our prints are all printed, which is ugly~

Next we introduce the log~

no no no~

Loguru third-party log library

We don't need the logging module that comes with python, we are introducing a third-party library today: Loguru

Loguru is a library which aims to bring enjoyable logging in Python.

install logurn

pip install loguru

This time we first create a mytest_02_02.py to eliminate the pytest framework to automatically capture the beginning of the test file.

"""
loguru use
"""
from assertpy import assert_that
from loguru import logger
import pytest
logger.debug('This is my first time using loguru')

Output result:

2022-07-06 23:12:35.809 | DEBUG    | __main__:<module>:7 - This is my first time using loguru

I fell asleep, continue tomorrow

Today we continue the loguru....

The printed log is saved to a file

Create a mytest_02_03.py

from loguru import logger
logger.add("mytest.log", rotation="500 MB")  # In this way, a mytest.log file is created. If the file is larger than 500m, it will be re-saved, and the following log information is stored in the file.

# The following functions are self-understood
logger.add("file_2.log", rotation="12:00")     # New file is created each day at noon

logger.add("file_3.log", rotation="1 week")    # Once the file is too old, it's rotated

logger.add("file_X.log", retention="10 days")  # Cleanup after some time

logger.add("file_Y.log", compression="zip")    # Save some loved space

Continue to modify mytest_02_03.py

from loguru import logger

logger.add("mytest.log", rotation="500 MB")  # In this way, a mytest.log file is created. If the file is larger than 500m, it will be re-saved, and the following log information is stored in the file.


logger.info('This is a info')  # file storage terminal will print
logger.debug('This is a debug')
logger.warning('This is a warning')
logger.error('This is a error')

continue:

Loguru favors the much more elegant and powerful {}formatting over%, logging functions are actually equivalent to str.format().

# loguru supports automatic string formatting
logger.info("If you're using Python {}, prefer {feature} of course!", 3.6, feature="f-strings")
# print must add format
print("If you're using Python {}, prefer {feature} of course!".format(3.6, feature="f-strings"))

When our project gets bigger and bigger, our py file has many opportunities, and a common log module will be called. If something goes wrong, we need to know which file\function to call: @logger.catch

Continue to modify mytest_02_03.py

from loguru import logger

logger.add("mytest.log", rotation="500 MB")  # In this way, a mytest.log file is created. If the file is larger than 500m, it will be re-saved, and the following log information is stored in the file.


@logger.catch
def my_function(x, y, z):
    # An error? It's caught anyway!
    return 1 / (x + y + z)


my_function(0, 0, 0) # Passing parameters in this way will definitely report an error, let's take a look at the output

Console output:

2022-07-07 23:30:07.902 | ERROR    | __main__:<module>:16 - An error has been caught in function '<module>', process 'MainProcess' (16084), thread 'MainThread' (15688):
Traceback (most recent call last):

> File "D:\code\pytest_test\test_2_day\my_test_02_02.py", line 16, in <module>
    my_function(0, 0, 0)
    └ <function my_function at 0x0000019D1CCE4310>

  File "D:\code\pytest_test\test_2_day\my_test_02_02.py", line 13, in my_function
    return 1 / (x + y + z)
                │   │   └ 0
                │   └ 0
                └ 0

ZeroDivisionError: division by zero

Process finished with exit code 0

The result output in the mytest.log file:

2022-07-07 23:30:07.902 | ERROR    | __main__:<module>:16 - An error has been caught in function '<module>', process 'MainProcess' (16084), thread 'MainThread' (15688):
Traceback (most recent call last):

> File "D:\code\pytest_test\test_2_day\my_test_02_02.py", line 16, in <module>
    my_function(0, 0, 0)
    └ <function my_function at 0x0000019D1CCE4310>

  File "D:\code\pytest_test\test_2_day\my_test_02_02.py", line 13, in my_function
    return 1 / (x + y + z)
                │   │   └ 0
                │   └ 0
                └ 0

ZeroDivisionError: division by zero

Ok, let's learn it~, we will encapsulate this log function method next.

We created one under the project directory: public_fun\log_fun.py name whatever you want

from loguru import logger
import os


# get project path
def get_pro_path():
    pro_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    return pro_path


def get_logger():
    logger.add(os.path.join(get_pro_path(), "mytest.log"), rotation="500 MB")
    return logger


We create a test case test_02_04.py

"""
loguru use
"""
from public_fun.log_fun import get_logger
from assertpy import assert_that
logger = get_logger()


def test_fun1():
    logger.info('I need to compare 1')
    assert_that(1).is_not_equal_to(1)

The content of mytest.log appears under the project directory is

2022-07-07 23:48:06.382 | INFO | test_02_02:test_fun1:10 - I need to compare 1

This will automatically bring the file\method\line number that calls him.

it's really awesome

If it doesn't feel great, please use the logging module and look at it later

2022-07-07 23:51

Tags: pytest

Posted by tuneout on Thu, 07 Jul 2022 23:56:15 +0930