Pytest concept

Pytest is a unit testing framework. Unit testing refers to checking and testing the correctness of the smallest units (functions, methods) of software in software development.

What does unit testing do?

1. Test discovery: find our test case from multiple files;

2. Test execution: execute according to certain order and rules and generate results;

3. Test judgment: judge the difference between the expected result and the actual result through assertions;

4. Test report: counted test progress, time and pass rate, and generated test report;

Unit testing framework is only one of the components of automatic testing framework. Also included in the automated testing framework are: design patterns, data-driven, keyword driven, encapsulation of global configuration files, log monitoring, Selenium and Requests secondary encapsulation, assertions, and report mail……

Basic usage of the decorator @pytest.mark.parametrize() in PyTest

All testing frameworks are data-driven. What is data-driven?

Data-driven: In fact, we put our test case data into Excel, YAML, CSV, mysql. Then change the test case execution results by changing the data.

@pytest.mark.parametrize(args_name,args_value)

Args_name: Parameter name

Args_value: The value of the argument (supported formats: list, tuple, dictionary list, field tuple, i.e. [], (), [{},{},{}], ({},{},{})).

Pytest default test case rules :(can be modified according to the pytest.ini configuration file)

1. The module name must start with test_ or _test.

2. The class name must start with Test.

3. The method name must start with test.

Method of use

Method 1: The most basic usage

Import PyTest class TestApi: @pytest.mark.parametrize('args', [' id ', 'id ',' id ', 'id ']) def test_01_api(self, args): print(args) if __name__ == '__main__': pytest.main(['-vs', 'test_api.py'])Copy the code

Execute the above code, the test_01_API use case is executed four times, respectively printing ‘zhang SAN ‘,’ Li Si ‘, ‘Wang Wu ‘,’ zhao six ‘. The -vs command displays detailed log information. Test_api.py indicates the file to execute.

Execution Result:

Method 2: The usage of unpacking

If we format the parameters we pass in, as shown in the figure below, as two lists, the test case will execute twice, passing two lists each time.

Now we pass in two parameter names, as shown in the figure below. Looking at the results, we see that the first element in each list is passed to name and the second element to age. This is how unpack is used, similar to the data-driven decorator DDT implemented in the UnitTest framework.

import pytest class TestApi: @pytest.mark.parametrize('name,age', [[' action ', 20], [' action ', 21]]) def test_01_API (self, name,age): print(name, age) if __name__ == '__main__': pytest.main(['-vs', 'test_api.py'])Copy the code

Pytest is data-driven in combination with YAML

Yaml description

Yaml is a data format stored in a data file that supports comments, newlines, and bare strings (minimum units of data)

Yaml purposes

(1) Used for global configuration files: environment, database information, account information, log format, report name.

(2) for interface automation inside some more complex multi-interface series.

(3) Used to write interface test cases.

Yaml syntax rules

(1) Case sensitive

(2) Like Python, hierarchy is represented by indentation

(3) It has nothing to do with how many layers are indent, only whether the left side is aligned

(4) #

Examples of YAML data composition

(1) Map object: key (space) value

(2) Array (list) : Start with a set of lines

The site to verify that the YAML file format or JSON file format is correct: www.bejson.com/

A profound

(1) Create a new yaml file data.yaml and write the following code:

Get - api_name: netease api_request: url: https://api.apiopen.top/getWangYiNews method: post headers: the content-type: application/json params: page: 1 count: 5 api_validate: - eq: {code: 200}Copy the code

(2) Create a Python file yaml_util.py that encapsulates the functions that read the data from the yaml file.

Def read_yaml(): with open('data.yaml', encoding='utf_8', mode='r') as f: def read_yaml(): with open('data.yaml', encoding='utf_8', mode='r') as f: data = yaml.load(f, Loader=yaml.FullLoader) return dataCopy the code

(3) Create a new Python file test_api.py to write test cases

import pytest
import requests
from pytest_yaml.yaml_util import read_yam

class TestApi:

    @pytest.mark.parametrize('args', read_yaml())
    def test_01_api(self, args):
        url = args['api_request']['url']
        method = args['api_request']['method']
        headers = args['api_request']['headers']
        params = args['api_request']['params']

        if method == 'get':
            requests.get(url)
        else:
            resp = requests.post(url, json=params, headers= headers)
            print(resp.json())

if __name__ == '__main__':
    pytest.main(['-vs', 'test_api.py'])
Copy the code

Running results:

(4) Add assertions

As shown in the figure above, get a list of assertions in a YAML file, all multiple assertions, iterate through with a for loop, assert with the Assert method, and run successfully.

The interface tests implemented above are the most basic, taking one interface, executing one test case, and only one assertion. When used in practice, this is far from enough.

The interface of actual combat

Interface for obtaining the token authentication code

Access Token interface is obtained from wechat open document for practice. The interface document is as follows:

The interface documentation shows that the method is Get and the interface address is api.weixin.qq.com/cgi-bin/tok… , the interface needs to pass in parameters grant_type, appID, and secret.

Access the interface using Python and print the value of the response to the console as follows:

import unittest
import requests

class TestApi(unittest.TestCase):
    def test_01_get_token(self):
        url = " https://api.weixin.qq.com/cgi-bin/token"
        params = {
            "grant_type": "client_credential",
            "appid": "xxxxxxxxxxxxx",
            "secret": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
        }
        resp = requests.get(url, params=params)
        print(resp.json())
Copy the code

Add assertions

AssertEqual (resp.status_code, 200) self.assertequal (resp.status_code, 200)

AssertIn (‘access_token’, resp.text) assertIn(‘access_token’, resp.text)

AssertEqual (dict_result[‘expires_in’], 7200) self.assertEqual(dict_result[‘expires_in’], 7200)

deserialization

Dict_result = json.load (resp.text) dict_result = json.load (resp.text)

Dict_result = resp.json()

import json import unittest import requests class TestApi(unittest.TestCase): def test_01_get_token(self): url = " https://api.weixin.qq.com/cgi-bin/token" params = { "grant_type": "client_credential", "appid": "xxxxxxxxxxxxx", "secret": } resp = requests. Get (url, params=params) print(resp.text, type(resp.text)) Dict_result = json.loads(resp.text) # # dict_result = resp.json() # assert # Assert whether the status code returned is 200 self.assertequal (resp.status_code, AssertIn ('access_token', 'access_token', 'access_token') AssertEqual (dict_result['expires_in'], 7200) # business assertion 2Copy the code

Gets the created tag of the public account

The interface documentation is as follows:

import unittest import requests class TestApi(unittest.TestCase): Def test_01_get_token(self) def test_01_get_token(self): url = " https://api.weixin.qq.com/cgi-bin/token" params = { "grant_type": "client_credential", "appid": "wx5046a51617ff683a", "secret": "334 c600a9fbbcadac918d5665d7b1d12"} resp = requests. Get (url, params = params) print (resp. Text, type (resp. Text)) # deserialization. Dict_result = resp.json() # Get access_token and save testapi.access_token = dict_result['access_token'] # AssertEqual (resp.status_code, AssertIn ('access_token', 'access_token', 'access_token') Self. assertEqual(dict_result['expires_in'], Def test_02_select_flag(self) def test_02_select_flag(self): url = " https://api.weixin.qq.com/cgi-bin/tags/get" params = { "access_token": TestApi.access_token } resp = requests.get(url, Params =params) print(resp.json()) self.assertequal (resp.status_code, AssertIn ('tags', resp.text) # Business assertionCopy the code

interface

Interface 2 requires the access_token returned by interface 1 to execute. How to associate the access_token?

Access_token = “”

Testapi. access_token = dict_result[‘access_token’]

(3) Pass the global variable access_token as a parameter to interface 2 “access_token”: testapi.access_token

(4) Global variables can be obtained and saved in yamL files.

Cookie, Session,Token authentication solutions

What is a cookie?

A cookie is a small piece of text information generated on the server and stored on the client. The format is dictionary, key-value pairs.

The classification of the cookie

Session level: saves memory and disappears when the browser closes.

Persistence: Keeps the hard drive and will be deleted only when it expires.

How do I view cookies?

How does cookie Implement authentication (Principle)

When the client visits the server for the first time, the server will generate cookies, which are then transmitted to the client in set-cookie through the response header. The client will automatically carry these cookies from 2-n requests.

Fatal weakness: Cookies are stored in the client, which is not secure for some sensitive information, such as user name, password and ID number.

Implement a login interface in Python and extract the token from the response.

The interface is a POST request, and the parameters and response results are as follows:

Send the request in Python as follows:

import requests
import unittest
import json

class TestApi(unittest.TestCase):

    def test_01_api(self):

        url = "http://api-store**************staff/login"

        jsontext = {
            "account": "188********",
            "password": "123456"
        }
        data = {
            "device_type": 30,
            "system": 2,
            "jsonText": json.dumps(jsontext)
        }

        headers = {
            "Content-Type": "application/x-www-form-urlencoded"
        }

        resp = requests.post(url, data=data, json=json,headers=headers)
        print(resp.text)


if __name__ == '__main__':
    unittest.main()
Copy the code

The result is as follows:

Retrieves the token value using a regular expression

Value = re.search('"token":"(.+?)) "', resp.text) print(value.group(1))Copy the code

Save the obtained token in a global variable

import re import requests import unittest import json class TestApi(unittest.TestCase): # define a global variable token = "" def test_01_api (self) : url =" http://api * * * * * * * * * * * / login "jsontext = {" account" : "188******", "password": "123456" } data = { "device_type": 30, "system": 2, "jsonText": json.dumps(jsontext) } headers = { "Content-Type": "application/x-www-form-urlencoded" } resp = requests.post(url, data=data, Value = re.search('"token":"(.+?)) print(resp.text) "', Testapi.token = value.group(1) print(testapi.token) if print(testapi.token) if __name__ == '__main__': unittest.main()Copy the code

If we need to pass cookies during the next interface test, we can define a global variable that holds cookies, test_cookies = “”, Extract cookies with test_cookies = resp.cookies and save them to the global variable test_cookies, passing cookies in the following interface test, namely: Requests. Post (URL, data=data, json=json, headers=headers, cookies=test_cookies).

The session authentication

When the user accesses the server for the first time, a sessionid will be saved on the server side. The sessionid is encrypted, and then the sessionid will be saved to the client side through cookies. Only the sessionid will be sent when requesting the server.

Class TestApi(unittest.testCase): # define a global variable session = "" def test_01_api(self): Sessionid res = testapi.session.get (url=url) print(TestApi.session) print(res.json()) if __name__ == '__main__': unittest.main()Copy the code

The Achilles heel of session authentication:

For the browser, sessionID is very useful, just need to save a string in the cookie, but the server must store all online user sessionID, so the more people online at the same time, the more overhead, seriously affect the server performance. When the number of users is very high, the server will crash.

Token authentication

All of the above solutions revolve around sessions, so what about using sessionids instead?

If sessionIDS are not applicable, how do you ensure that the data is generated by the server? How do you test that? Where does the user information reside?

Therefore, some people think of generating encrypted string according to certain rules. The server only verifies but does not store it. As long as the verification passes, the user information is stored in encrypted string, so that performance and CORS(cross-domain resource sharing) can be solved.

The original link: blog.csdn.net/wtf0712/art…

When a user logs in, he or she is sent a token, which he or she only needs to carry the next time the user requests it.

Token encryption mode:

Symmetric encryption: DES AES

Two-key encryption: RSA

Encryption but not decryption: MD5 SHA

Classification of tokens:

Access_token: The time limit is 15 minutes

Refresh_token: Usually 15 days

Similarities and differences between Cookie, Session, and Token:

Similarity: Both are used for authentication and are generated by the server.

The difference between:

  1. Cookies are stored on the client and sessions are stored on the server. Session security is higher than cookies. So in general, important information is put in session and less important information is put in cookie.

  2. The session is stored in the server memory, and the token is stored in the file or database on the server. The advantage of the token is that it saves server resources more than the session. The token only needs to be decrypted on the server.

In the process of continuous technological progress, the above gradually failed to meet the needs of users, and new problems emerged: third-party payment, banking and financial projects have higher requirements for security, so the interface signature Sign emerged, about which we will not explain in this article.

Afterword.

I am really too busy recently, all kinds of overtime, have no time to study, I will write here first, later have time to supplement.