Interface automated testing: Python+Pytest+Requests+Allure

This project implements the interface test of Daily Cost :

  • Python+Requests sends and processes HTTP protocol request interface
  • Pytest as a test executor
  • YAML management test data
  • Allure to generate test reports.

This project is based on pytestDemo to do its own implementation.

1. Project structure and installation and deployment

project structure

  • api : interface encapsulation layer, such as encapsulating HTTP interface as Python interface
  • commom : various tools for reading data from files
  • core : requests request method encapsulation, keyword return result class
  • config : environment, database connection and other configurations
  • data : test data file management
  • operation : keyword encapsulation layer, such as encapsulating multiple Python interfaces as keywords
  • pytest.ini : pytest configuration file
  • requirements.txt : related dependency package files
  • testcases : test cases
  • api_test : single interface test
  • scenario_test : scenario/business process test

Installation and deployment

  • Deploying the Daily Cost App: Tutorial
  • Download the source code of this test project , install the corresponding dependencies through pip pip3 install -r requirements.txt, and modify the corresponding content in setting.ini according to the actual situation
  • Enter pytestrun test
  • If you want to use Allure to view the generated test report, you need to install the Allure service first:brew install allure

2. Environment configuration

  • Defined in the config-setting.ini fileapi_root_url
  • Implement the load_ini() method in common-read_data.py to read the configuration file
  • api_root_urlCall it where it needs to be used load_ini(data_file_path)to read the corresponding value

3. Encapsulate HTTP request

  1. Encapsulate requests request method: encapsulate methods such as GET, POST, PUT, DELETE sent in requests into the RestClient class
  2. Define the tested API interface Request: Create a collection class corresponding to the request according to the domain in the api folder, such as class User(RestClient), and define each interface information, such as the login interface:
def login(self, **kwargs):         
    return self.post("/login", **kwargs)

4. Keyword encapsulation

Keywords should be of some business significance. When encapsulating keywords, you can only encapsulate one interface, or call multiple interfaces to complete.

For example, if we want to test a record , the interface will only return the ID of the bill after the interface is called successfully, and we also need to call the query bill details interface to help determine whether each field is consistent with the input, then we can test like this:

  • First, 记一笔-查看明细encapsulate the operation as a keyword, in this keyword, call the record and query the bill detail results in turn, and you can customize the return result of the keyword
  • Then, when writing a test case, call the keyword directly to test, then you can return the result of the keyword, and when asserting, you can also directly assert the result returned by the keyword

Another example is to query the statistical results of monthly bills . One interface can independently complete the business query operation. We only need to call this interface in the keyword.

Back to this project, the specific code logic is as follows:

  1. In the operation folder, the keywords are organized according to the domain file
  2. Define the data structure class returned by the keyword in coreResultBase
  3. Define keywords. When calling the corresponding API request, you need to explicitly pass the interface request parameters and define the return result
def bill_monthly_stat(date, token):
   header = {
       "Content-Type": "application/json",
       "Authorization": "Bearer " + token
   }
   param = {"date": date}
   res = bill_details.get_bill_monthly(params=param, headers=header)

   return ResultBase(res)

There is only one request encapsulated in the keywords in this project.

5. Single interface test

Take 记一笔interfaces as an example.

  • Define interface and keywords
// api -> bill.py : 定义接口
def create_new_bill(self, **kwargs):
    return self.post("/bill", **kwargs)

// operation -> bill.py : 定义关键字
def bill_create(category_id, type, amount, note, date, token):
    payload = {
        "categoryId": category_id,
        "type": type,
        "amount": amount,
        "note": note,
        "date": date
    }
    header = {
        "Content-Type": "application/json",
        "Authorization": "Bearer " + token
    }
    res = bill.create_new_bill(json=payload, headers=header)

    return ResultBase(res)
  • Interface test class
// testcases -> api_test -> bill -> test_bill_create.py
class TestBillCreate():
    @mark.smoke
    @mark.parametrize('category_id, type, amount, note, date, status_code, message', 
                    [
        ("5442d3b8-9d4a-4654-bf0b-d2249efef190", "EXPENSE", 100.01, "note1111test", "2021-12-01", 200, "操作成功"),
        ("66c22fad-be9d-481d-a445-c57d266bf938", "INCOME", 1000.01, "note1111test", "2021-12-01", 200, "操作成功")
        ])
    def test_bill_create_success(self, category_id, type, amount, note, date, status_code, message, token):
        result = bill_create(category_id, type, amount, note, date, token)
        assert result.response.status_code == status_code
        assert result.message == message
        assert result.response.json()["data"]["id"]
  • @mark.smokeIt uses the mark marking function of pytest. When running, use the command pytest -m smoketo run only the use cases marked as smoke
  • @mark.parametrizeIt is the variable parameterization function of pytest, which can realize data-driven testing. As shown above, if there are two parameterized data, the use case will be executed twice with these two data
  • There is a parameter when calling bill_create token, which is actually conftest.pydefined in the file
  • The assert in pytest uses python's built-in assertion library

6. YAML file management test data

In the above example, we @mark.parametrizedirectly wrote the specific test data above the use case when using it. In order to improve the efficiency of later modification and maintenance, we usually separate test data and use cases, that is, we can use yaml files to manage test data separately, and conftest.py can help read data.

  • Define the yaml file: data -> api_test_data.yml
test_bill_create_success:
  # category_id, type, amount, note, date, status_code, message
  - ["5442d3b8-9d4a-4654-bf0b-d2249efef190", "EXPENSE", 100.01, "note1111test", "2021-12-01", 200, "操作成功"]
  - ["66c22fad-be9d-481d-a445-c57d266bf938", "INCOME", 1000.01, "note1111test", "2021-12-01", 200, "操作成功"]
  • keyThe function name corresponding to the test casetest_bill_create_success
  • -Indicates that value is an array
  • conftest.pyRead the corresponding test data in
import pytest
import os
from common.read_data import data 

BASE_PATH = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
def get_data(yaml_file_name):
    try:
        data_file_path = os.path.join(BASE_PATH, "data", yaml_file_name)
        yaml_data = data.load_yaml(data_file_path)
    except Exception as ex:
        pytest.skip(str(ex))
    else:
        return yaml_data

api_data = get_data("api_test_data.yml")
  • Read data from yaml file when parameterizing
@mark.parametrize('category_id, type, amount, note, date, status_code, message', 
                    api_data["test_bill_create_success"])

7. API scenario testing

When doing API testing, in addition to the verification of the input and output of a single interface, the test of business scenarios composed of multiple interfaces connected in series is also essential.

To put it simply, let’s take the home page after logging in as an example. The interface call is: Login -> Query the current month’s bill list -> Query the current month’s bill statistics.

  • Define the scenario test class
// testcases -> scenario_test -> test_get_one_month_bill.py
import allure
import pytest
from operation.user import login_user
from operation.bill import one_month_bill_list_get_by_date, bill_monthly_stat

@pytest.mark.core
class TestGetOneMonthBill:

    @allure.title("01: user[yuxiaomeng] login")
    @allure.story('story_1')
    def test_user_login(self, core_env):
        result = login_user('yuxiaomeng', '20211030.y')
        assert result.status_code == 200
        assert result.data["token"]
        core_env["token"] = result.data["token"]

    @allure.title("02: get homepage info - bill details list")
    @allure.story('story_1')
    def test_get_current_month_monthly_bill_list(self, core_env):
        result = one_month_bill_list_get_by_date(core_env["date"], core_env["token"])
        assert result.status_code == 200
        assert len(result.data) == 2
        assert result.data[0]["date"] == "2021-11-11"
        assert result.data[0]["expense"] == 510.5

    @allure.title("03: get homepage info - bill monthly statistics ")
    @allure.story('story_1')
    def test_get_current_month_bill(self, core_env):
        result = bill_monthly_stat(core_env["date"], core_env["token"])
        assert result.status_code == 200
        assert result.data["expense"]
  • Which core_envis used to pass test data between interfaces
// testcases -> scenario_test -> conftest.py
import pytest

@pytest.fixture(scope='session')
def core_env():
    return {"date": "2021-11"}

8. Allure generates a test report

For detailed usage of allure-pytest, please refer to the official documentation . Only a brief introduction is given here.

  • Add the --alluredir parameter when running the test to save the report to the specified folder:pytest --alluredir=/tmp/my_allure_results
  • View the report after running:allure serve /tmp/my_allure_results

The following is the supporting information. For friends who do [software testing], it should be the most comprehensive and complete preparation warehouse. This warehouse also accompanied me through the most difficult journey. I hope it can help you too!

Software testing interview applet

The software test question bank maxed out by millions of people! ! ! Who is who knows! ! ! The most comprehensive quiz mini program on the whole network, you can use your mobile phone to do the quizzes, on the subway or on the bus, roll it up!

The following interview question sections are covered:

1. Basic theory of software testing, 2. web, app, interface function testing, 3. network, 4. database, 5. linux

6. web, app, interface automation, 7. performance testing, 8. programming basics, 9. hr interview questions, 10. open test questions, 11. security testing, 12. computer basics

Information acquisition method:

Guess you like

Origin blog.csdn.net/myh919/article/details/131810989