Python interface automated testing (1)

1. Since we have these interface testing tools, why do we need to automate the interface?

1. For agile development, the number of interfaces is generally large, and the team implements interface testing and version control.
2. The function is too rigid, and some interfaces cannot be implemented at all (complex encryption interface, signature interface, etc.)
3. There are many interfaces of different protocols in the interface project.
4. Troubleshooting and locating interface problems are inconvenient, combined with packet capture.
5. There is no way to generate beautiful reports.
6. Multi-interface serial connection, database verification, and log monitoring.
7. Some companies do web automation + interface automation.

Two, python+requests module

The requests third-party library is mainly used to send http requests and do interface automation.

#安装
pip install requests

3. The global view of requests for interface automation

ask
requests. get() send get request
requests. post() send post request
requests. delete() send delete request
requests .put() send put request
requests. request() The core method
import requests
rep = requests.request();
response
rep.text Returns the string's data (in text format)
rep.content Return data in byte format (image, file)
rep.json() Return data in dictionary format (json format)
rep.status_code status code
rep.reason return status information
rep.cookies return cookie information
rep.encoding return encoding format
rep.headers Return response header information

4. Interface combat

Request method: get post put delete
Request parameter type: key-value pair, JSON format, file format

unittest, pytest management use case framework:

The premise is to install pytest

pip install pytest

pytest default rules:
1.py file must start with test _ or end with _ test .
2 Class name must start with Test
3. Test case must start with test_

Notice:

1、get请求通过params传递参数。
2、post请求通过json或者data传参。他们的区别是什么?
	data
		数据报文: dict字典类型,那么默认情况下请求头: application/x-www-form-urlencoded,
				表示以form表单的方式传参,格式: a=1&b=2&c=3
		数据报文: str类型,那么默认情况下: text/plain(如果是字典格式需要转换成str格式传参)
	json
		数据报文:不管是dict还是str类型,默认都是application/json ,格式: ({
    
    "a":1,"b".2)
		
data = {
    
    "tag": {
    
    "id": 134, "name": "广东人"}}
rep = requests.post(url=url, data=json.dumps(data))

json.dumps(data)序列化	把字典格式的数据转换成str格式.
json.loads(data)反序列化	把str格式转换成字典格式

总结:
data只能传递简单的只有键值对的dict或者是str格式。
json一般只能传dict格式(简单和嵌套都可以)
#3、文件传参files,且一定要open
data={
    
    
     "media":open(r"E:\shu.png","rb")
}
rep = requests.post(url=url, files=data)
#  以下代码运行不起来,但是写法没错
import pytest
import requests

class TestSendRequest:
    access_token=""
    def test_get_token(self):
        # 发送get请求
        url = "https://api.weixin.qq.com/cgi-bin/token"
        data = {
    
    
            "grant_type": "client_credential",
            "appid": "自己找素材",
            "secret": "自己找素材"
        }
        rep = requests.get(url=url, params=data)
        print(rep.json())
        TestSendRequest.access_token = rep.json()["access_token"]

    def test_edit_flag(self):
        # 发送post请求(data和json只需要传一个,data和json的区别)
        url = "https://api.weixin.qq.com/cgi-bin/token/tags/update?access_token=" + TestSendRequest.access_token + ""
        data = {
    
    "tag": {
    
    "id": 134, "name": "广东人"}}
        rep = requests.post(url=url, json=data)
        print(rep.json())

if __name__ == '__main__':
    #-vs 打印调试信息
    pytest.main(['-vs'])

1. Cookie authentication: Basically, the interface of the web page needs to perform cookie authentication. (not commonly used)
( Token and request header are given, but the request still fails, and cookie authentication is required )

import re
import pytest
import requests

class TestSendRequest:
    cks=""
    
    #需要带请求头的接口以及需要cookie关 联的接口如何测试?
    def test_start(self):
        url = "http://47.107.116.139/phpwind/"
        rep=requests.get(url=url)
        print (rep.text)
        #通过正则表达式获取鉴权码
        TestSendRequest.csrf_token= re.search( 'name="csrf_token" value="(.*?)"', rep.text)[1]
        print(TestSendRequest.csrf_token)
        TestSendRequest.cks=rep.cookies

    #请求需要带请求头的接口
    def test_login(self) :
        url = "http://47.107.116.139/phpwind/index.php?m=u&c=login&a=dorun"
        data = {
    
    
            "username" : "msxy",
            "password" :"msxy",
            "csrf_token": TestSendRequest.csrf_token,
            "backurl": "http://47. 107.116.139/ phpwind/",
            "invite": ""
        }
        headers = {
    
    
            "Accept": "application/json,text/ javascript, / ; q=0.01",
            "X一Requested-With" : "XMLHttpRequest"
        }
        rep = requests. post (url=url, data=data , headers=headers,cookies=TestSendRequest.cks )
        print (rep.json() )


if __name__ == '__main__':
    #-vs 打印调试信息
    pytest.main(['-vs'])

2. Implement cookie authentication through session (commonly used)

import re
import pytest
import requests

class TestSendRequest:
	csrf_token=""
    session = requests.session()
    
    #需要带请求头的接口以及需要cookie关 联的接口如何测试?
    def test_start(self):
        url = "http://47.107.116.139/phpwind/"
        rep=requests.get(url=url)
        print (rep.text)
        #通过正则表达式获取鉴权码
        TestSendRequest.csrf_token= re.search( 'name="csrf_token" value="(.*?)"', rep.text)[1]
        print(TestSendRequest.csrf_token

    #请求需要带请求头的接口
    def test_login(self) :
        url = "http://47.107.116.139/phpwind/index.php?m=u&c=login&a=dorun"
        data = {
    
    
            "username" : "msxy",
            "password" :"msxy",
            "csrf_token": TestSendRequest.csrf_token,
            "backurl": "http://47. 107.116.139/ phpwind/",
            "invite": ""
        }
        headers = {
    
    
            "Accept": "application/json,text/ javascript, / ; q=0.01",
            "X一Requested-With" : "XMLHttpRequest"
        }
        rep = TestSendRequest.session.post (url=url, data=data , headers=headers)
        print (rep.json() )


if __name__ == '__main__':
    #-vs 打印调试信息
    pytest.main(['-vs'])

Interface automation testing framework encapsulation

The first step is to unify the request method

rep=requests.request(request method, address, parameters...)

def test_get_token(self):
        # 发送get请求
        url = "https://api.weixin.qq.com/cgi-bin/token"
        data = {
    
    
            "grant_type": "client_credential",
            "appid": "wx6b11b3efd1cdc290",
            "secret": "106a9c6157c4db5f602991873819529d"
        }
        rep = requests.request("get",url=url, params=data)
        print(rep.json())
        TestSendRequest.access_token = rep.json()["access_token"]

Pytest global view

1. It can be combined with all automated testing tools selenium, requests, and appium to realize web automation, interface automation, and app automation; 2.
Skip use cases and rerun failed use cases;
3. Combine allure to generate beautiful test reports;
4, and Jenkins continuous integration;
5. There are many powerful plug-ins.

1. Common operations (1)

Create a requirements.txt file in the root directory of the project Note
: ( # is my own explanation for the convenience of reading the code, please delete the copy)

#pytest框架
pytest

#生产html测试报告
pytest-html

#多线程运行
pytest-xdist

#改变测试用例的执行顺序
pytest-ordering

#失败用例重跑
pytest-rerunfailures

#生产allure测试报告
allure-pytest
#在命令窗口使用 安装这个文件里面的插件
pip install -r requirements.txt	 

2. Common operations (2) Operation mode

Create a python.ini file in the root directory

#提示这是pytest文件
[pytest]
#执行方法,-m "smoke" 只执行冒烟用例,要想执行其他用例  删除-m以及后面的
addopts = -vs -m "smoke"
#文件路径
testpaths = ./ui
#文件以test_开头
python_files = test_*.py
#类名以Test开头
python_classes = Test*
#用例以test_开头
python_functions = test_*

#对用例进行分组 在用例上@pytest.mark.smoke,就执行加了这样的用例
markers =
    smoke:maoyan

If no python.ini file is created
, the output in the main program is as follows:

if __name__ == '__main__':
    '''
    v   输出更加详细的运行信息
    -s  输出调试信息
    -n  多线程运行
    --reruns数字  失败用例重跑
    --html='报告的路径'
    '''

    #写了pytest.ini
    pytest.main()

    # pytest.main(['-vs','-n=2'])
    # pytest.main(['-vs','--reruns=2'])
    # pytest.main(['-vs','--html=./report.html'])
    

3. Common operations (3) Front and rear

setUp()/tearDown() is executed once before/after each use case
setUp_class()/tearDown_class() is executed once before/after each class

Implement part of the front

Partial preposition:
@pytest.fixture ( scope = "scope", params = "data-driven", autouse = "automatic execution", ids = "custom parameter name", name = "rename")
scope: function (default), class , module , package/session

import requests
import re
import pytest

#部分前置
@pytest.fixture(scope="function")
def conn_database():
    print("连接数据库")
    
	#可以通过yield唤醒teardown的功能,就是返回,yield和return都有返回数据的意思
	#但是yield返回多次及多个数据,return只返回一次且return后面的代码不执行
    yield
    print("关闭数据库")```

class Test:
    def test_edit_flag(self,conn_database):
        url=''
        data={
    
    "tag":{
    
    "id":134,"name":"小李"}}
        rep=Test.session.request('post',url,json=data

In general:
@pytest.fixture() and conftest.py file together use
conftest.py file
1. conftest.py : The file is a method of storing **@pytest.fixture()** separately, which can implement multiple py files Shared pre-configuration
2. conftest.py : No need to import and use it directly, you can use it directly
3. conftest.py : There can be multiple or different levels

import pytest
@pytest.fixture(scope="function")
def conn_database():
    print("连接数据库")
    yield
    print("关闭数据库")

4. Interface automation test framework encapsulation (interface associated encapsulation)

1. Create a common folder and create a yaml_util.py file

import os
import yaml
class YamlUtil:
    #读取extract.yml文件
    def read_extract_yaml(self,key):
        with open(os.getcwd()+"./extract.yml",mode="r",encoding="utf-8") as f:
            value=yaml.load(stream=f,Loader=yaml.FullLoader)
            return value[key]

    #写入extract.yml文件
    def read_extract_yaml(self,data):
        with open(os.getcwd()+"./extract.yml",mode="w",encoding="utf-8") as f:
            yaml.dump(data=data,stream=f,allow_unicode=True)

    #清除extract.yml文件
    def clearn_extract_yaml(self):
        with open(os.getcwd()+"./extract.yml",mode="w",encoding="utf-8") as f:
            f.truncate()

2. Create extract.yml file
3. Create conftest.py file

import pytest
from common.yaml_util import YamlUtil

#autouse  自动执行,无需调用
#scope 作用域(session)
@pytest.fixture(scope="session",autouse=True)
def clearn_Yaml():
    YamlUtil().clearn_extract_yaml()

5, pytest affirmations

# result ==>{"errcode": 0,"message":"数据返回成功"}
result = rep.json()
# 第一种
assert result['errcode'] == 0
#第二种
assert 'errcode' in rep.json()
#比较多个或者用and
assert 'errcode' in rep.json()
assert 'message' in rep.json()
assert 'errcode' in rep.json() and 1==1

6. allure-pytest generates allure test report

6.1. Download allure from the official website:

https://github.com/allure-framework/allure2/releases
Download the .zip package, put it in a path without Chinese, and then configure E:\allure-2.13.7\bin to the path of the environment variable.

6.2. Restart pycharm and pass: allure --version verification (if pycharm is not opened, skip it)

6.3. Executing commands

(1) Generate a temporary json file report in the temp directory , write - -alluredir ./temp in the pytest.ini file to create a temp directory
in the current directory

[pytest]
#执行方法
addopts = -vs --alluredir ./temp
#文件路径
testpaths = ./ui
#文件以test_开头
python_files = test_*.py
#类名以Test开头
python_classes = Test*
#用例以test_开头
python_functions = test_*

(2) Generate the allure report ( in the reports directory ) through the temporary json file , write
os.system("allure generate temp -o reports --clean") in the all.py file and create the reports directory
in the current directory

import pytest

if __name__ == '__main__':
    pytest.main()
    os.system("allure generate temp -o reports --clean")

6.4. Customization of allure reports

Guess you like

Origin blog.csdn.net/qq_44895262/article/details/126559695
Recommended