Python 3, how simple is the Pytest unit test framework? Everyone can get started in 8 minutes!!

1. Introduction

Little loser: brother fish, why don't you talk about the technology of test development recently, such as
Xiaoyu: I'll go ~ ~ you've agreed to bring up this matter together?
Little loser: why do you say that?
Xiaoyu: because recently, a sister complained to me about why she didn't talk about the knowledge of test development, which was developed by the whole
Loser: isn't it?
Xiaoyu: brother, I have difficulties too ~~
Little loser: don't fix those useless ones, just one today!!!
Fish: exactly~~

Xiaoyu's blog said unittest framework , there are also many examples in it. If you don't understand it, you can have a look.
Today, let's share the framework, but this time it's the unit test framework: Pytest.

Xiaoyu remembers writing an article on the composition of the test framework,
This includes the necessary knowledge of the test framework composition in various stages such as function, performance and automation,
If you don't understand, you can take a look at Xiaoyu's blog< Test framework composition of test development knowledge>.
First cut a picture and see:

Here, let's just talk about the unit test framework of Pytest. Let's not talk about anything else!!

2. Introduction to Pytest

2.1 introduction stage

2.1. 1 run test cases

All theories are prepared for actual combat,
Therefore, our first step is to give examples and direct actual combat!

Write a simple test case with the file name "test_sample.py"

# pytest test_sample.py
def inc(x):
    return x + 1

def test_answer():
    assert inc(3) == 5

Both methods are very simple,

  • test_answer() asserts the objective function inc;
  • pytest test_sample.py run test case

Let's look at the running results

The test results show that a test case is run, and the result is red, indicating failure. The error message shows that AssertionError is thrown on line 7 of the code. You can change the code to make the test case green.

This test case involves three simple rules of pytest:

  • Test module to test_ Prefix naming
  • Test cases (functions) are also represented by test_ Prefix naming
  • The result can be judged by assert

2.1. 2. Exception handling

Catching exceptions and exception handling are necessary conditions in each piece of code,
Of course, pytest also supports exception capture,
Method: use with + pytest Raises caught an exception in the objective function:

# -*- coding:utf-8 -*-
# @Time   : 2021-09-05
# @Author : Carl_DJ

import pytest

def f():
    raise SystemExit(1)

def test_mytest():
	#Catch exception
    with pytest.raises(SystemExit):
        f()

2.1. 3 test class

Of course, pytest also supports test classes,
Function of test class: used for test grouping

# -*- coding:utf-8 -*-
# @Time   : 2021-09-05
# @Author : Carl_DJ

class TestClass:
	#test_ start
    def test_one(self):
        x = "this"
        assert "h" in x
	#test_ start
    def test_two(self):
        x = "hello"
        assert hasattr(x, "check")

Here, it's all based on test_ At the beginning, it's the same as unittest.

If not test_ At the beginning, it cannot be called.

2.1. 4 run test scripts automatically

If a suit folder has multiple test case scripts,
We just need to enter a pytest to run all the test scripts.
As shown below

This is the lazy mode.

2.2 advanced skills

2.2.1 parametrize

As the saying goes, the code does not have parameters, but changes parameters in two lines!
Therefore, when you can parameters, try to parameters, regardless of whether the reconstruction is bitter or not.
Let's look at the usage of parameter first, as follows:

Add the following before the test case:
@pytest. mark. Parameter ("parameter name", list data)
Parameter name: used to receive each item of data and serve as the parameter of the test case.
List data: a set of test data.

Look at the example
Without adding parameter, let's see how to write test cases

def test_eval():
    assert eval("3+5") == 8
    assert eval("'2'+'4'") == "24"
    assert eval("6*9") == 54

It looks troublesome,
Let's optimize the parameter again to see if it's much simpler

#Parameterize test cases using parameterize
@pytest.mark.parametrize("test_input,expected", [
    ("3+5", 8),
    ("'2'+'4'", "24"),
    ("6*9", 54)
])
def test_eval_1(test_input, expected):
    assert eval(test_input) == expected

After reading this code, it is very concise.
Let's see what parametrize does.

  • First, adjust the parameters of the test function as input and expectation;
  • Then fill in the parameter value in parameter;
  • Function parameters will be assigned automatically at run time.

In this way, the test conditions are added, and there is no need to change the test_eval_1, add the condition array.

2.2.2. mark

mark is a label that marks which test cases are executed and which are not executed.

#label
@pytest.mark.slow
def test_mark():
    print("test mark")
    # Simulate test cases that are time-consuming to run
    time.sleep(10)
    assert 5 == 5

Then add pytest. Exe to the directory INI file to configure pytest:

[pytest]
markers =
    slow: marks tests as slow (deselect with '-m "not slow"')

Use the following command to skip marked functions and speed up the test:

pytest test_sample.py -m "not slow"

You can also run only marked functions

pytest  -m slow

2.2.3 fixture

fixture is similar to setup/teardown of unittest, but it is more powerful than this.
for instance

# -*- coding:utf-8 -*-
# @Time   : 2021-09-05
# @Author : Carl_DJ

import pytest

#Set fixture
@pytest.fixture
def first_entry():
    return "a"


#Set fixture
@pytest.fixture
def second_entry():
    return 2


#Set fixture
@pytest.fixture
def order(first_entry, second_entry):
    return [first_entry, second_entry]


#Set fixture
@pytest.fixture
def expected_list():
    return ["a", 2, 3.0]


def test_string(order, expected_list):
    order.append(3.0)

    # Assert
    assert order == expected_list

Of course, fixture s can also be nested, and order nested first_entry and second_entry.

Little loser: what should I do if I need a database link to test the case written in the database?
Little fish, it's not difficult. fixture can also be done.
Write conf test. In the test case directory py

@pytest.fixture
def database_connection():
    # coding...
    ...

2.2.4 plugin&&hook

You can write plug-ins plugin and hook of pytest to extend pytest.
First create a directory a, and then create conf test. In directory a Py and test_sub.py two files.

#Create conf test. In directory a py
def pytest_runtest_setup(item):
        # Run each use case under directory a
        print("setting up", item)
        
# Create test under directory a_ sub.py
def test_sub():
    pass

Using pytest a/test_sub.py --capture=no will load the plugin and hook written by us. You can see the following words in the console:

...
a/test_sub.py setting up <Function test_sub>

Knock on the blackboard:
Using pytest_runtest_setup can implement similar functions in the test framework.

3. Summary

The above are some common functions of pytest summarized by Xiaoyu. Is it also very simple.
In retrospect, we talked about those postures today!

  • Test directories are generally named by tests and src
  • The test module uses test_ prefix
  • The Test class uses the Test prefix and does not need to inherit other parent classes
  • Test cases also use test_ prefix
  • Parameterize can be used for parameterization
  • You can use mark to label test cases
  • You can use fixture to simulate test conditions
  • Use pytest INI file to configure pytest
  • You can write plug-ins and hoo extensions to pytest

More about pytest,
Can continue to pay attention Xiaoyu's blog
You can also read the official documents, Click download.

Keywords: Python unit testing

Added by isedeasy on Wed, 15 Dec 2021 02:16:48 +0200