Advanced advanced testing project, summary of Pytest automated testing framework (4)


foreword

1. Not only the test function test_app of pytest can be parameterized, but also the initialization function before_test can be parameterized

Key points: Parameterization of test cases + parameterization of initialization and clearing functions Parameterization of initialization and clearing functions can realize appium's multi-terminal testing

There are many ways to parameterize the initialization and clearing function:
before_test initialization function injects parameters, because the port in print(f'connect appium service {port}') needs to be changed.

@pytest.fixture(scope='module',params=[(4723,),(4727,)]): parameterization of the initialization cleanup function

Add params parameter in the initialization function decorator to pass parameters, port=request.param[0] to call the parameters in params

#初始化清除函数的参数化:只传单个参数            import pytest
@pytest.fixture(scope='module',params=[(4723,),(4727,)])     #初始化清除函数的参数化params
def before_test(request):           
	port=request.param[0]               #param[0],假如注入多个参数一个port和一个data--需要params传元组,
												  #params=[(4723,100),(4727,200)],一个参数的话不需要写成列表嵌套元素,                                      #params[0]代表获取元组第一个
	print("启动被测app")
	print(f'连接appium服务{
      
      port}')
	yield   #后面写清除动作,
	after_test()
							  #request是pytest的对象,我们在用对象里面的方法的时候pycham不会自动帮我们取显示名字,                                      #它也不知道request里面到底什么内容
def after_test():
	print('关闭被测app')
	print('断开appium服务')

@pytest.mark.usefixtures('before_test')    
@pytest.mark.parametrize('psw',['boss123','boss456'])
def test_app(psw):                                   
	print('测试boss app')
	print(f'登录测试账号{
      
      psw}')

if __name__ == '__main__':
	pytest.main(['pytest_ywt.py','-s'])
#初始化清除函数的参数化:传多个参数                     import pytest
@pytest.fixture(scope='module',params=[(4723,'xiaomi'),(4727,'meizu')])  
def before_testquest):           
	port=request.param[0]          #param[0],假如注入多个参数一个port和一个data,需要params传元组,params=[(4723,100),(4727,200)],
									#一个参数的话不需要写成列表嵌套元素,request.params[0]代表获取元组第一个
	device=request.param[1]          #request.param[1]对应元素里面第二个参数,
	print(f"在{
      
      device}启动被测app")
	print(f'连接appium服务{
      
      port}')
	yield   #后面写清除动作,
	after_test()

						#request是pytest的对象,(固定写法:request.param)                                #我们在用对象里面的方法的时候pycham不会自动帮我们去显示名字,它也不知道request里面到底什么内容
def after_test():
	print('关闭被测app')
	print('断开appium服务')

@pytest.mark.usefixtures('before_test')                    
@pytest.mark.parametrize('psw',['boss123','boss456'])
def test_app(psw):           

	print('测试boss app')
	print(f'登录测试账号{
      
      psw}')

if __name__ == '__main__':
	pytest.main(['pytest_ywt.py','-s'])

2. The execution code of the pytest framework can also be executed by directly entering commands in cmd

xxx\test_case> pytest -s

Executing in the test_case directory will run all the test files in the test_case file (test cases beginning with test)

3. Distributed

Each module of the set use case is independent, what is the precondition to do it in the module, for example, to test 10 modules, use association to do it, can not do distributed (concurrent execution)

Each module can be customized to execute that module independently, but it cannot be done if the correlation is too strong;
it is best to make each interface independent (preconditions are well done) and do not make interfaces that are too correlated;
each layer can Do environment cleaning and customization (packages, modules, classes, functions) layering, and lay the foundation for subsequent mark (which use cases are executed at fixed points) and distribution.

Distributed: It is necessary to achieve isolation of use cases (low coupling, high cohesion), and it is very risky to run serial use cases and it is difficult to maintain

3000 requests, all independent, and then distributed to do (efficiency increased several times - dozens of times)

4. Distributed implementation

The core point of distribution: Encapsulation design: independent of each other, login and courses are independent of each other, at least the modules as units must be independent of each other, the encapsulation is independent of each other, and the interface use cases are preferably independent of each other in order to be distributed

One: pytest distributed environment construction and theoretical introduction:

The first step: Install a library pip install pytest-xdistdistributed operation plug-in, which can be distributed (this library has two operation modes)

Operation mode:
Serial: sequential operation, serial operation, from beginning to end
Parallel: pytest-xdist has two types of distribution, one is multi-core, and the other is multi-machine

Multi-core: Single machine with multiple cores (running at the same time) using the -n parameter
Computer multi-core may be false or true: hyper-threading technology (8 cores become 16 cores), true 8 cores and false 8 cores -
number of cpus: hardware, several cpu slots , i9900.i710-General computer counts as one cpu, single cpu, the server may have multiple cpu
cores: the number of cores of the computer.
Number of logical cores: The number of logical cores can be virtualized, and 8 cores can be changed to 16 cores (hyperthreading technology)

For multi-core, the multi-core of xdist itself is generally done with the number of logical cores

Multi-machine (virtual machine can be used) - you need to set up an environment, multiple machines are very troublesome, install the environment, and download the library

What to do if there are many test cases:
distributed two cases  
Large amount: multi-machine (requires file report collection and setting up an environment, which is more troublesome to do)
single-machine multi-core, it is very simple, just add the -n parameter (it will take some time to do ui and Time optimization is especially obvious when waiting)

Serial operation: it is run by threads. Python is a process with many threads in it. If you run a process, you need multiple machines to do it. If the use case design is not good, there will be big problems, and the data will be wrong (the use case must be independent)

Parallel and multi-machine: use cases must be well designed, otherwise the data is prone to errors, and the logic is independent (no correlation, no context) and independent data and code encapsulation

Distributed runtime code

#验证单机多核分布式
import pytest
import time

def test_01():
	time.sleep(3)
	print("-----test01-----")

def test_02():
	time.sleep(3)
	print("-----test01-----")


if __name__ == '__main__':
	# pytest.main(["test_xdist.py","-sq"])          #这是串行跑的   6s
	pytest.main(["test_xdist.py", "-sq","-n","8"])     #单机多核并行   加"-n","8" 参数  ,用8个核来跑,5.41s,时间少了
	#或者测试用例文件目录下 cmd,输入 pytest test_xdist.py -n 8  也可以    这样cmd里执行看到的结果更直观,
	#多核来跑在ui里面时间提升很大,ui里面很多地方需要sleep,等待元素(有等待的的提升比较大)多核跑更快
	#有等待的情况用多核跑效果越明显

The serial operation itself runs according to the thread. Python itself is a process, and
if there are many threads in it, it is more appropriate to run it on multiple machines.

The use case must be well designed, otherwise the data is prone to errors, and the logic is independent (no correlation, no context)----independence of data and code encapsulation

pytest cmd executes multiple module use cases: pytest test_xdist.py test_login.py -sq runs two .py files (write multiple runs multiple)
pytest cmd executes multiple package use cases: pytest test_xdist test_login -sq: run test_xdist package and The test_login package
can also run two packages of different modules, add the package path case/test_xdist.py case2/test2_xdist.py

5. Customized implementation of mark tags for pytest use cases

All interfaces do not need to run all (smoke, customized execution of some specified business,) "-m", "test_lesson_add"

pytest framework mark tag, the mark is very rich, mark tag

mark tag: For pytest, we can add mark in front of every module, every class, every method and use case, so that we can only run modules, classes, and use cases with the mark tag when pytest is running

In this way, it is convenient for us to execute all use cases, a certain module use case, a certain process use case, and a certain individual use case when we choose to execute automation. In short, we can execute all use cases under a single label

mark can mark things at different levels (classes, functions, and methods can all be marked) files do not need to be marked (it can be customized and executed)

@pytest.mark.lessson_moudle Put a label on the test class. The name of the label is lesson_moudle to identify the course module. Each function and class can be labeled (similar to another name). Select a certain label to run a certain one (flexible and convenient)

Run as usual with nothing selected, (run all, no limit)

The mark label pytest may report an error, PytestUnknownMarkWarning error: it is a mark warning of a label, the entire pytest does not recognize you, but it will not report an error, it is just a warning.
Eliminate warnings (increase label column, equivalent to label declaration)

Label statement writing: create a pytest.ini file in the teach_sq folder (pycham needs to install the ini plugin file-setting-plugins (search ini) community version does not seem to work)

pycham can't find it can be installed offline

teach_sq
pytest.ini-----文件内容如下,相当于pytest的mark标签声明一下            #文件内容,markers后面把标签全部写上,    lessson_moudle   一个类级别的mark标签名,            #test_lesson_add,test_lesson_list,test_lesson_delete   三个函数级别的mark标签名称            #  mark标签名称: 描述   这样的格式来写,前面声明标签名称,后面是描述(随便写)
[pytest]                    
markers=
	lessson_moudle: teach_lesson	# (标签名: 描述  这样的格式前面lesson_modle和test_lesson_add等是mark的标签名称,声明一个标签:冒号后面一定要加空格,规范)                                  

It is not recommended to write Chinese in the following description, and an error will be reported (transcoding is required, but this file is called by python itself)
test_lesson_add: teach_lesson
test_lesson_list: teach_lesson
test_lesson_delete: teach_lesson

Customize an interface to execute test_lesson_add: "-m", "test_lesson_add"

pytest.main(["test_lesson01.py", "-s", "-m", "test_lesson_add"]) ---- -m can be realized, mark customized execution

Customized execution of multiple interfaces – logic or on the line: "-m", "test_lesson_add or test_lesson_delete"

pytest.main([“test_lesson01.py”,“-s”,“-m”,“test_lesson_add or test_lesson_delete”])

Exclusion method excludes one - customization except for a certain interface does not run, others run - "-m", "not test_lesson_add"

pytest.main(["test_lesson01.py", "-s", "-m", "not test_lesson_add"])----Except for the test_lesson_add interface, others are running

exclude multiple - "-m", "not (test_lesson_add or test_lesson_delete)"

pytest.main([“test_lesson01.py”,“-s”,“-m”,“not (test_lesson_add or test_lesson_delete)”])

Filter test case code:

import pytest

@pytest.mark.zzzzz
def test_001():
    print('test_001')

def test_002():
    print('test_001')

if __name__ == '__main__':
    pytest.main(["test1.py",'-s','-m','zzzzz'])

Customized execution: (assembly process)

mark tag: convenient assembly process
-k: matching and filtering case name (can be standard (full name) or fuzzy matching) - refers to the module, -k is similar to -m, with or and not.

But -k only runs all use cases, and then there are exclusion modes, selected modes, and other modes (-k is written in cmd)

pytest -k test_lesson01.py: Execute the test case of the test_lesson01.py module (sq can not be written, just not printed, there will be a lot of information to print when sq is executed incorrectly,)

Select all, all modules in the test package are selected: pytest -k test, (modules with similar functions are named with the same word, so that -k can be matched together)

lesson_1.py and lesson_2.py: want to run two files pytest -k lesson (default fuzzy match lesson)

-m: Select the corresponding tag (label, mark needs to be tagged to customize execution, the other two k and v do not need to be tagged)
-v: node, you want to run a certain thing in it: (node ​​specified a certain one)

Example:

pytest_lesson.py::Test_lesson::test_01

pytest -v pytest_lesson.py::Test_lesson::test_01

-sq: (simplified print print information)
-s: output print print
-q: simplified output
sq, error message is displayed when there is an error, or fail has a lot of failure information, write sq to print when there are many prints (success does not need to be written)

Skip/Conditional Skip: Judge whether this thing should run or not through the upper and lower conditions, (two types) skip

Skip (skip without conditions, specify skip, no conditions need to be met) skip

@pytest.mark.skip("跳过test_lesson_add") #无条件跳过

Write @pytest.mark.skip("skip test_lesson_add") in front of the interface function,
this interface will be unconditionally skipped and not executed (it will be described in the report)

Conditionally skip skip if

@pytest.mark.skipif(1==1,reason="条件需要前面完成某一个步骤--前面条件为真的时候则跳过函数,不为真执行函数") #有条件的跳过

Streamlining needs to skip interfaces, 1, 2, 3,

2 is executed only when 1 is true, and 1 is not executed and 2 is not executed, just skip)
Where does the condition come from, and make a judgment between the expected and the actual (find a precondition to judge whether it is true)
if you log in If it fails, then the course interface should not be taken away (you can write it like this) Login failed without sessionid

Usage scenario: Don't run away if the previous action fails.
Preconditions, or it is detected that the server python environment is not required, do not run.
There are requirements on the version (the system environment and the interpreter version can be used as preconditions for whether the code should be executed or not). The label can only go to the
interface (method layer), and cannot be assigned to the use case. The use case is made through data-driven

There is another way to write custom execution:
name and surname----(The following instructions can be executed directly in the cmd console command)

Execute only the test cases of Test1, execute the command: pytest -sq test_xt.py::Test1
py file to class, class level (:: level relationship)

Just want to execute test_3 in Test2, execute command: pytest -sq test_xt.py::Test2::test_3py file, class, interface method

Execute multiple conditions at the same time: Execute the command:pytest -sq test_xt.py::Test1::test01 test_xt.py::Test2::test02

You can also filter based on the use case name -k, execute the command:pytest -sq -k 2 test_xt.py

The following is the most complete software test engineer learning knowledge architecture system diagram in 2023 that I compiled

1. From entry to mastery of Python programming

Please add a picture description

2. Interface automation project actual combat

Please add a picture description

3. Actual Combat of Web Automation Project

Please add a picture description

4. Actual Combat of App Automation Project

Please add a picture description

5. Resume of first-tier manufacturers

Please add a picture description

6. Test and develop DevOps system

Please add a picture description

7. Commonly used automated testing tools

Please add a picture description

Eight, JMeter performance test

Please add a picture description

9. Summary (little surprise at the end)

Never stop, meet the challenge; with courage, go beyond the limit. Diligence and wisdom create brilliance, and passion and hard work light up the future. Believe in your own ability and potential, overcome difficulties, and march towards the other side of success.

Go forward bravely, not afraid of hardships; with faith, chasing dreams. The strength of struggle comes from persistence and hard work, and every effort will bloom the fragrance of results. Believe in your own infinite possibilities, embrace challenges, and create your own brilliant life. Don't forget the original intention, forge ahead, success will be with you!

No matter how many difficulties you encounter, stick to your beliefs and be unyielding. Believe in your ability and potential, water the flowers of your dreams with sweat. Every effort will accumulate strength, and every struggle will move towards a higher peak.

Guess you like

Origin blog.csdn.net/m0_70102063/article/details/132023800