Pytest + request + allure implement interface automation framework

Time:2021-10-26
catalogue
  • preface:
  • 1、 Brief introduction
  • 2、 Code structure and framework process
  • 3、 Detailed functions and instructions
  • 4、 Allure report and email
  • 5、 Subsequent optimization

preface:

Interface automation refers to the automation at the interface level of analog program. Because the interface is not easy to change and the maintenance cost is less, it is deeply loved by major companies.
Interface automation includes two parts: functional interface automation test and concurrent interface automation test.
This article focuses on the first, functional interface automation framework.

1、 Brief introduction

Environment: MAC, python 3, pytest, allure, request

pytest==3.6.0
Pytest allure adapter = = 1.7.10 (deprecated)
pytest-rerunfailures==5.0
configparser==3.5.0
PyYAML==3.12
requests==2.18.4
simplejson==3.16.0
----------------------------------------
Updated on April 30, 2020
pytest==5.3.1
allure-pytest==2.8.6
allure-python-commons==2.8.6
⚠ Note: pytest allure adapter has been abandoned and changed to allure pytest;
When installing allure pytest, you need to uninstall pytest allure adapter

Process: read yaml test data – generate test cases – execute test cases – generate allure Report
Design description of module class:

Request.pyEncapsulate the request method and support multi protocol extension (get \ post \ put)
Config.pyRead configuration files, including configuration of different environments and email related configuration
Log.pyPackage log recording methods, including debug, info, warning, error and critical
Email.pyEncapsulate the SMTP lib method and send email notification of the running results
Assert.pyEncapsulate assert method
run.pyCore code. Define and execute use case sets and generate reports

Yaml test data format is as follows:

---
Basic:
  Dec: "basic settings"
  parameters:
    -
      url: /settings/basic.json
      data: slug=da1677475c27
      header: {
                 "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko)\
                  Chrome/67.0.3396.99 Safari/537.36",
                 "Content-Type": "keep-alive"
              }

2、 Code structure and framework process

1. The code structure is shown in the figure below:

Code structure.jpg

2. The framework process is shown in the figure below:

Framework process.jpg

3、 Detailed functions and instructions

1. Define configuration file config.ini

The file distinguishes between the test environment [private_debug] and the formal environment [online_release] and defines relevant configuration items respectively, and the [mail] part is mail related configuration items

#HTTP interface test framework configuration information
 
[private_debug]
#Debug test service
tester = your name
environment = debug
versionCode = your version
host = www.jianshu.com
loginHost = /Login
loginInfo = [email protected]&password=123456
 
[online_release]
#Release formal service
tester = your name
environment = release
versionCode = v1.0
host = www.jianshu.com
loginHost = /Login
loginInfo = [email protected]&password=123456
 
[mail]
#Send mail message
smtpserver = smtp.163.com
sender = [email protected]
receiver = [email protected]
username = [email protected]
password = 123456

2. Package after reading yaml test data

See Section 1 for an example of yaml test data. One interface can define multiple case data, get_ Parameter is an encapsulated method for reading yaml data. After cyclic reading, multiple case data are stored in the list.


class Basic:
    params = get_parameter('Basic')
    url = []
    data = []
    header = []
    for i in range(0, len(params)):
        url.append(params[i]['url'])
        data.append(params[i]['data'])
        header.append(params[i]['header'])

3. Write use cases

class TestBasic:
    @allure.feature('Home')
    @allure.severity('blocker')
    @allure.story('Basic')
    def test_basic_01(self, action):
        """
            Case description: viewing basic settings without logging in
        """
        conf = Config()
        data = Basic()
        test = Assert.Assertions()
        request = Request.Request(action)
 
        host = conf.host_debug
        req_url = 'http://' + host
        urls = data.url
        params = data.data
        headers = data.header
 
        api_url = req_url + urls[0]
        response = request.get_request(api_url, params[0], headers[0])
 
        assert test.assert_code(response['code'], 401)
        assert test.assert_ Body (response ['body '],'error', u 'please register or log in before continuing operation.)
        assert test.assert_time(response['time_consuming'], 400)
        Consts.RESULT_LIST.append('True')

4. Run the whole framework run.py

if __name__ == '__main__':
    #Define test set
    args = ['-s', '-q', '--alluredir', xml_report_path]
    self_args = sys.argv[1:]
    pytest.main(args)
    cmd = 'allure generate %s -o %s' % (xml_report_path, html_report_path)
 
    try:
        shell.invoke(cmd)
    except:
        Log. Error ('failed to execute the use case, please check the environment configuration ')
        raise
 
    try:
        mail = Email.SendMail()
        mail.sendMail()
    except:
        Log. Error ('failed to send mail, please check mail configuration ')
        raise

5. Err.log instance

[ERROR 2018-08-24 09:55:37]Response body != expected_ msg, expected_ MSG is {“error”: “please register or log in before continuing 9.}, body is {” error “:” please register or log in before continuing.}
[ERROR 2018-08-24 10:00:11]Response time > expected_time, expected_time is 400, time is 482.745
[ERROR 2018-08-25 21:49:41]statusCode error, expected_code is 208, statusCode is 200

6. Assert part code

def assert_body(self, body, body_msg, expected_msg):
        """
        Verify the value of any attribute in the response body
        :param body:
        :param body_msg:
        :param expected_msg:
        :return:
        """
        try:
            msg = body[body_msg]
            assert msg == expected_msg
            return True
 
        except:
            self.log.error("Response body msg != expected_msg, expected_msg is %s, body_msg is %s" % (expected_msg, body_msg))
            Consts.RESULT_LIST.append('fail')
 
            raise
 
    def assert_in_text(self, body, expected_msg):
        """
        Verify that the response body contains the expected string
        :param body:
        :param expected_msg:
        :return:
        """
        try:
            text = json.dumps(body, ensure_ascii=False)
            # print(text)
            assert expected_msg in text
            return True
 
        except:
            self.log.error("Response body Does not contain expected_msg, expected_msg is %s" % expected_msg)
            Consts.RESULT_LIST.append('fail')
 
            raise

7. Request part code

def post_request(self, url, data, header):
        """
        Post request
        :param url:
        :param data:
        :param header:
        :return:
        """
        if not url.startswith('http://'):
            url = '%s%s' % ('http://', url)
            print(url)
        try:
            if data is None:
                response = self.get_session.post(url=url, headers=header)
            else:
                response = self.get_session.post(url=url, params=data, headers=header)
 
        except requests.RequestException as e:
            print('%s%s' % ('RequestException url: ', url))
            print(e)
            return ()
 
        except Exception as e:
            print('%s%s' % ('Exception url: ', url))
            print(e)
            return ()
 
        # time_ Consuming is the response time, in milliseconds
        time_consuming = response.elapsed.microseconds/1000
        # time_ Total is the response time, in seconds
        time_total = response.elapsed.total_seconds()
 
        Common.Consts.STRESS_LIST.append(time_consuming)
 
        response_dicts = dict()
        response_dicts['code'] = response.status_code
        try:
            response_dicts['body'] = response.json()
        except Exception as e:
            print(e)
            response_dicts['body'] = ''
 
        response_dicts['text'] = response.text
        response_dicts['time_consuming'] = time_consuming
        response_dicts['time_total'] = time_total
 
        return response_dicts

4、 Allure report and email

1. See the following figure for an overview of allure report:

Allure report.jpg

2. See the following figure for email:

Email.jpg

5、 Subsequent optimization

1. Integrate Jenkins and generate allure report using Jenkins plug-in
2. Automated testing of multithreaded concurrent interfaces
3. Interface encryption

This is the end of this article about the implementation of interface automation framework by pytest + request + allure. For more information about pytest interface automation framework, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!