Pytest Web Automation from Baicao Garden to Sanwei Bookstore…

The full code is given at the bottom!

Development environment:

  • Pytest 6.2.5
  • Python 2.7.16
  • Allure 2.14.0
  • PyCharm 2021.2.3
  • system mac

What do you like?

Pytest interface automation from Baicaoyuan to Sanwei Bookstore…

Nonsense not to say, directly on dry goods!!

PyTest

The default rule for PyTest

When pyTest is defined, the package name and class name must start with Test by default.

Let’s start with a simple example!The execution result is as follows:

test_11.py ...                                                           [ 33%]
test_12.py ...                                                           [ 66%]
test_13.py ...                                                           [100%]
Copy the code

As you can see, the default execution is the progress shown

Output details [-s]

# Used to turn off capture information to print print information
pytest.main(['-s'])
Copy the code

Note that:

  • Success is indicated by..
  • Execution failures are denoted by F

If this is not obvious, use:

Display specific test case information [-v]

#T ODO -s Is used to turn off the capture information to output the printed information
# TODO -v displays specific information
pytest.main(['-s'.'-v'])
Copy the code

Simplified test case information [-q]

# TODO -q simplifies output information
pytest.main(['-s'.'-q'])
Copy the code


Execute specific test cases [-k]

# TODO -k runs a test case that contains a specific string
pytest.main(['-s'.'-v'.'-k'.'b'])
Copy the code

test_13.py::test_function_b ======test_function !!!!!!!! b!!!!!!!! PASSEDCopy the code

Abort test cases executed until they fail [-x]

# todo-x terminates the test as soon as a failed test case is executed
pytest.main(['-x'])
Copy the code

Execute a specific use case

Scenario: TEST_DEMO1 To execute a test_demo2 test case

It is now impossible to implement..

# TODO only executes a specific use case
pytest.main(['-s'.'. '.'.. /test_demo2/test_21.py::test_function_01'])
Copy the code


Another way to write it crudely is to execute all test cases

TODO executes all test cases
pytest.main(['-s'.'.. '])
Copy the code

Test case failure % D end [–maxfail=2]

# TODO test cases fail 2 and exit
pytest.main(['--maxfail=2'])
Copy the code


Marking [missile]

TODO marks only test cases that mark slow
pytest.main(['-m'.'slow'])
Copy the code

Note that the word slow is written casually, but it could be written in other ways, such as this:

pytest.main(['-m'.'abc'])
Copy the code


Pytest original test report [–junit-xml=./report/xxx.xml]

TODO generates the original test report
pytest.main(['--junit-xml=./report/ original test report.xml '])
Copy the code

Execute a single use case

TODO executes a single use case
pytest.main(['-s'.'test_11.py'])
Copy the code


Error use case executed %d times alone [–reruns=2]

The TODO failed use case is executed twice
pytest.main(['-s'.'--reruns=2'.'test_11.py'])
Copy the code

Error cases separately perform % d times, each time interval % d seconds [‘ — reruns = 2 ‘, ‘- reruns – delay = 3]

The TODO failed use case is executed 2 times and waits 3 seconds each time
pytest.main(['-s'.'--reruns=2'.'--reruns-delay=3'.'test_11.py'])
Copy the code

Function and pre-module/post-module

TODO test cases are executed before the start
def setup_module() :
    print("{}setup_module{}".format("*" * 20."*" * 20)),TODO is executed at the end of the test case
def teardown_module() :
    print("{}teardown_module{}".format("*" * 20."*" * 20)),TODO is executed before each test case function starts
def setup_function() :
    print("{}setup_function{}".format("-" * 20."-" * 20)),TODO is executed at the end of each test case
def teardown_function() :
    print("{}teardown_function{}".format("-" * 20."-" * 20)),# TODO Each test case function is executed before it starts and after setup_function()
def setup() :
    print("{}setup{}".format("+" * 20."+" * 20)),# TODO is executed at the end of each test case before teardown_function()
def teardown() :
    print("{}teardown{}".format("+" * 20."+" * 20)),def test_0() :
    print("test0")


def test_1() :
    print("test1")


def test_2() :
    print("test2")


def test_3() :
    print("test3")
Copy the code

The running results are as follows:

test_14.py ********************setup_module********************
--------------------setup_function--------------------
++++++++++++++++++++setup++++++++++++++++++++
test0
.++++++++++++++++++++teardown++++++++++++++++++++
--------------------teardown_function--------------------
--------------------setup_function--------------------
++++++++++++++++++++setup++++++++++++++++++++
test1
.++++++++++++++++++++teardown++++++++++++++++++++
--------------------teardown_function--------------------
--------------------setup_function--------------------
++++++++++++++++++++setup++++++++++++++++++++
test2
.++++++++++++++++++++teardown++++++++++++++++++++
--------------------teardown_function--------------------
--------------------setup_function--------------------
++++++++++++++++++++setup++++++++++++++++++++
test3
.++++++++++++++++++++teardown++++++++++++++++++++
--------------------teardown_function--------------------
********************teardown_module********************
Copy the code

It’s all mindless, it’s all routine… A little taste will understand!!

Summary:

pytest instructions
-s Output details
-v Display specific test cases
-q Simplify test case output
-x Test cases are executed until they fail
-k Execute specific test cases
-maxfail=2 Failure to execute two test cases ends
‘-m’ missile ‘ Play tag
–junit-xml=./report/xxx.xml Original test report
–reruns=2 The error use case is executed twice separately
‘–reruns=2’, ‘–reruns-delay=3’ The error use case is executed two separate times, three seconds apart

Operations in the PyTest class

The default operation is the sameNote:

  • Class names start with Test by default
  • Method names start with test by default

By default, it starts with test, which proves that it can be modified. Don’t worry.

Class pre-function/post-function,and pre-module/post-module

Test code:


class TestDemo31:
    TODO test cases are executed before the start
    @staticmethod
    def setup_class() :
        print("{}setup_class{}".format("*" * 20."*" * 20)),TODO is executed at the end of the test case
    @staticmethod
    def teardown_class() :
        print("{}teardown_module{}".format("*" * 20."*" * 20)),TODO is executed before each test case function starts
    @staticmethod
    def setup_method() :
        print("{}setup_method{}".format("-" * 20."-" * 20)),TODO is executed at the end of each test case
    @staticmethod
    def teardown_method() :
        print("{}teardown_method{}".format("-" * 20."-" * 20)),# TODO Each test case function is executed before it starts and after setup_function(self)
    @staticmethod
    def setup() :
        print("{}setup{}".format("+" * 20."+" * 20)),# TODO is executed at the end of each test case before teardown_function(self)
    @staticmethod
    def teardown() :
        print("{}teardown{}".format("+" * 20."+" * 20)),def test_01(self) :
        print("Test Data 1")

    def test_02(self) :
        print("Test Data 2")

    def test_03(self) :
        print("Test Data 3")

Copy the code

Use:

import pytest

if __name__ == '__main__':
    pytest.main(['-s'.'-q'.'test_31.py'])
Copy the code

Test results:

********************setup_class******************** --------------------setup_method-------------------- + + + + + + + + + + + + + + + + + + + + setup++ + + + + + + + + + + + + + + + + + + test data1.++++++++++++++++++++teardown++++++++++++++++++++ --------------------teardown_method-------------------- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- setup_method -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + + + + + + + + + + + + + + + + + + + + setup++ + + + + + + + + + + + + + + + + + + test data2.++++++++++++++++++++teardown++++++++++++++++++++ --------------------teardown_method-------------------- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- setup_method -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- + + + + + + + + + + + + + + + + + + + + setup++ + + + + + + + + + + + + + + + + + + test data3
.++++++++++++++++++++teardown++++++++++++++++++++
--------------------teardown_method--------------------
********************teardown_module********************
Copy the code

This is similar to the preposition and postposition of functions, so there is no more explanation..

pytest.fixture

First, use:It’s the first parameter that matters herescopeHe has several types:

  • Each function or method is called
  • Class class level Each test class is run only once
  • Module is called once for each.py file at the module level
  • Session Session level Each session needs to be run only once. All methods, classes, and modules in the session share this method

See this article for details on several uses of fixtures.

The skip and skipIf

Concept:@pytest.mark.skipMarked test cases are not executed.

Parametrize parameterized

Concept: Test cases are executed repeatedly.

Look directly at the function:

Writing is not fixed, for example:The thing to notice here is that I have to match the same color.


Global configuration [conftest.py]

What is global configuration: PyTest preferentially scans this file, and what is defined here can be used by the entire project, usually in the root directory.

Note that you can’t change the name: conftest.py

Extension: Change the default value

Take a look at the current directory structurePrevious knowledge: If executed in the root directorypytest.main()All test cases that meet the criteria will be executed,

For example, test_demo4/test_41.py or test_demo4/test_42.py

In any case, a file in test_demo4/a will not execute because it does not meet the rule that the package name starts with test

Simply create the pyTest.ini file in the root directory and specify the directory to execute!

The thing to notice herepytest.iniYou can’t just give it a name, you have to give it a name, otherwise PyTest won’t be able to scan.

Scope of PyTest.ini: current directory and subdirectories

Let’s look at defining other rules:

pytest.inicode

[pytest]
# specify the directory to test
testpaths = test_demo4/a

# specify specific [file] rules
python_files = auto*.py test_*.py


# specify specific [class] rules
python_classes = Auto* PY_TEST_* Test*


Specify specific [test case] rules
python_functions = auto* test_*
Copy the code

allure

What is the allure?

Allure is a very elegant tool for generating test reports

He was so elegant that he had to install the environment

Sidebar: Allure is json and decorator based for test reporting, so it generates a lot of JSON files at run time and uses them through decorators!

MAC installation only requires 2 steps,win students to baidu [fist]

  • Step 1: Brew Install Allure
  • PIP install allure- Pytest

How to verify the installation:

Allure — Version # Check out allure

Or the old routine, the simplest use!

You can open it directly by right clicking

Index.html opens with:

The common allure decorator

Rating:

  • Epic’s largest module [Level 1]
  • Feature Characteristics [Level 2]
  • Story Scene [Level 3]
  • Title User title
  • The testcase url
  • Issue a bug address
  • Step Use case steps
  • Severity () The level of the use case

How does epic/Feature work together

This code is a lot, but very simple, must be fine taste it!!

Feature with story is similar:

Look at the renderings directly!

allure.title

Allure. Title just fixes the titleMore advanced uses are:This is not limited to changing the title, other things can be changed:

Such as:


Other Common Operations

  • @allure.severity(“blocker”)
  • @allure. Feature (” henan “)
  • @allure. Story (” Zhengzhou city “)
  • Testcase (“www.kaifa.baidu.com”) # The right path
  • @allure. Issue (“www.baidu.com”) # Wrong path

Use Case level (allure.severity) :

  • Blocker block defect
  • Critical Critical blocking function defective
  • Normal normal defect
  • 【 Interface does not match THE UI 】
  • 5. Trivial a slight defect or nonspecification.

Here’s one tiny detail to notice:


Clear previously generated jsonData [‘–clean-alluredir’]

The problem:

As you can see, there are a lot of JSON files to prove that it will not overwrite the previous JSON data, here is a line of code to do it!


Only perform test cases at a use-case level [‘–allure- Severities ‘, ‘Blocker ‘]

Remember there were a lot of them before, such as Shanxi, Shandong, etc., because zhengzhou, Henan was set as blocker level, so the test case only shows this!

Enable local service, Intranet sharing!

What is local service? Make your test report available to others!

os.system('allure serve {}'.format('allure_json_data'))
Copy the code

After running will generate an address, MAC is through Java to enable the local service!

The address here is not correct, you should give your real IP address,

MAC: terminal/console: ifconfig win: CMD: ipconfig

The final link after obtaining this number is:http://192.168.3.128:54739/

The complete code

I’ve been writing for a day. If this article helps you, please click the free like button. Thank you.

If you have any questions or are missing something, please leave them in the comments section and add them as soon as you see them!

Original is not easy, your praise is the biggest support for me!

What do you like?

Pytest interface automation from Baicaoyuan to Sanwei Bookstore…