Interface automated testing practice: interface framework modification, dynamic parameterization and data forgery

1. Foreword

This article mainly explains the framework construction and modification of Python interface automated testing, automated test case design, dynamic parameterization form of use case design in interface testing, etc. This article will skip some of the framework construction content. Without further ado, let’s do it together. Take a look.

2. Practical exercises

2.1 Interface Introduction

We first use an interface as the starting point. This interface is the login interface, and the request method is POST. After logging in, you can perform various operations. The basic information is as follows:

2.2 Interface excel test case

According to the login interface document, design the test case:

2.3 framework common directory

Test cases belong to data, so we must read excel. We also have configuration files and a log system. These are all common content. We can first add the corresponding code module to common:

"""There is an easier way to read excel. This method is suitable for novices to learn and understand"""
import openpyxl

def read_excel(file_path, sheet_name):
    """Read data in excel"""
    workbook = openpyxl.load_workbook(file_path)
    sheet = workbook[sheet_name]
    values = list(sheet.values)
    workbook.close()
    title = values[0]
    rows = values[1:]
    new_rows = [dict(zip(title, rows)) for rows in rows]
    return new_rows
"""Log system"""
import logging


def get_logger(logging_name="Collector",
               logger_level="DEBUG",
               stream_level="DEBUG",
               file=None,
               file_level="INFO",
               fmt="%(asctime)s--%(levelname)s--%(filename)s--%(lineno)d--%(message)s"):
    """Get the logger collector"""
    logger = logging.getLogger(logging_name)
    logger.setLevel(logger_level)
    stream_handler = logging.StreamHandler()
    stream_handler.setLevel(stream_level)
    logger.addHandler(stream_handler)

    fmt_obj = logging.Formatter(fmt)
    stream_handler.setFormatter(fmt_obj)

    # Determine whether there is a file. If so, initialize file_handler. If there is no file, do not execute it.
    if file:
        file_handler = logging.FileHandler(file, encoding="utf-8")
        file_handler.setLevel("INFO")
        logger.addHandler(file_handler)
        file_handler.setFormatter(fmt_obj)

    return logger


log = get_logger()
"""yaml reading results"""
importyaml


def read_yaml(file, encoding="utf-8"):
    with open(file, encoding="utf-8") as f:
        data = yaml.safe_load(f)
    return data

2.4 Test case design

Create a new test_login in the testcase directory to test login and implement excel reading and data driving. After obtaining the use case data, we first print and look at the data:

import unittest
import requests
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data


# retrieve data
data = read_excel(path_config.case_path, "login")

@ddt
class TestLogin(unittest.TestCase):
    @list_data(data)
    def test_login_success(self, case_data):
        print(case_data)

The complete code added is as follows:

import unittest
import requests
import json
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data


# retrieve data
data = read_excel(path_config.case_path, "login")

@ddt
class TestLogin(unittest.TestCase):
    @list_data(data)
    def test_login_success(self, case_data):
        print(case_data
        """
        1. The first step is to get the response data
        2. Obtain expected results
        3. Comparison of expected results and actual results
        """
        # Convert the json format string into a dictionary to avoid reading the string instead of the dictionary format when reading.
        json_data = json.loads(case_data["data"])
        headers = json.loads(case_data["headers"])
        expect = json.loads(case_data["expected"])
        response = requests.request(
            method=case_data["method"],
            url=case_data["Api_Url"],
            json=json_data,
            headers=headers
        )
        actual = response.json()
        self.assertEqual(actual["code"], expect["code"])

2.5 Use case design optimization

Create setting.py in the config directory, add the corresponding host domain name, and then splice the URLs:

# Domain name
host = "http://IP:port"
"""Fragment code"""
response = requests.request(
            method=case_data["method"],
            # Perform splicing and import settings before splicing.
            url=setting.host + case_data["Api_Url"],
            json=json_data,
            headers=headers
        )

In addition, we also need to perform assertion exception catching, and the complete code is modified again:

import logging
import unittest
import requests
import json
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data
from config import setting


# retrieve data
data = read_excel(path_config.case_path, "login")

@ddt
class TestLogin(unittest.TestCase):
    @list_data(data)
    def test_login_success(self, case_data):
        print(case_data)
        """
        1. The first step is to get the response data
        2. Obtain expected results
        3. Comparison of expected results and actual results
        """
        # Convert the json format string into a dictionary to avoid reading the string instead of the dictionary format when reading.
        json_data = json.loads(case_data["data"])
        headers = json.loads(case_data["headers"])
        expect = json.loads(case_data["expected"])
        response = requests.request(
            method=case_data["method"],
            url=setting.host + case_data["Api_Url"],
            json=json_data,
            headers=headers
        )
        actual = response.json()
        try:
            self.assertEqual(actual["code"], expect["code"])
            log.info(f"Test case passed: {case_data}")
        except AssertionError as err:
            log.error(f"Test case failed: {case_data}, error message: {err}")
            # After the test case fails to capture, use raise to throw it
            raise err

3. Dynamic parameterization

For example, when we design a registration interface test case, we will encounter an obvious bottleneck. The mobile phone number has not been registered. The registration can be successfully completed when the automated test case is executed for the first time, but it cannot be registered on the second time. When you execute the test case for the second time, you will find that the mobile phone number already exists, so the test case will fail when executed for the second time. In the face of this situation, there are several solutions:

"""
Solutions:
1. Every time you open excel manually and delete it, re-enter a new mobile phone number.
2. Query the mobile phone number in the database. If the mobile phone number already exists, delete the mobile phone number in the database.
3. The last digit of your existing mobile phone number + 1
4. Randomly generate a mobile phone number

Idea analysis:
1. Although the first method can be solved, it requires manual replacement every time it is executed, which is inconvenient to maintain.
2. Although mobile phone numbers can be queried and deleted, real projects often do not easily perform database deletion operations, and a registered mobile phone number will have a table association, and in most cases the test does not have permission to delete it.
3. This is also a solution. We can add + 1 to the 11th digit every time. The disadvantage is that we will eventually encounter numbers that may conflict with other mobile phone numbers and the execution will fail. However, the efficiency is much higher than 1 and 1. 2
4. The final method is also dynamic parameterization. Mark the data that needs to be replaced. When the loop traverses the mark, use a randomly generated number to replace the mark so that it can pass smoothly when executing the use case.

"""

Dynamic parameterization is to solve this type of problem, so that the mobile phone number can be continuously and randomly changed, so that each execution will not cause the use case to fail due to the duplication of mobile phone numbers (using dynamic parameterization may still randomly change the registered number, but the probability is extremely low), and randomly generating a mobile phone number requires data forgery.

4. Data forgery

In the field of automated testing, data forgery is not something that undermines system security, but it is the hope that test case data can be automatically generated and the data conforms to certain rules, such as mobile phone numbers, email addresses, etc. Data forgery can be used in automated registration modules, or in login or other text input boxes to detect certain input rules.

Data forgery library in Python – faker library, install it through pip first:

import faker

# Initialize the faker object and specify the generation rule area as China
fk = faker.Faker(locale="zh_CN")
result = fk.phone_number()
print(f"Mobile phone number:{result}")

# Randomly generate an address
company = fk.company()
print(f"Address:{company}")

# Randomly generate a company
address = fk.address()
print(f"Company:{address}")

# Randomly generate a city
city = fk.city()
print(f"city:{city}")

In addition to the standard forgery library that can provide forgery, we can also formulate a rule in the way we want:

def generate_new_phone():
    phone = "1" + random.choice(["3", "5", "7", "8", "9"])
    for i in range(9):
        num = random.randint(0, 9)
        phone + = str(num)
    return phone


print(f"Functional mobile phone number:{generate_new_phone()}")

Simple encapsulation of forgery library functions. If you write data forgery code in a framework, you can put it in common and import it from common to generate some data:

import faker

def generate_new_phone():
    fk = faker.Faker(locale="zh_CN")
    result = fk.phone_number()
    return result
# Modified fragment code (if you have any questions about the fragment code, please refer to the previous article):
@ddt
class TestLogin(unittest.TestCase):
    @list_data(data)
    def test_login_success(self, case_data):
        json_data = case_data["json"]
        if "#new_phone#" in json_data:
            new_phone = data_forgery.generate_new_phone()
            json_data = json_data.replace("#new_phone", new_phone)

Finally: The following is the supporting learning materials. For friends who do [software testing], it should be the most comprehensive and complete preparation warehouse. This warehouse has also accompanied me through the most difficult journey. I hope it can also help you. ! [100% free without any tricks]

Software testing interview applet

A software test question bank that has been used by millions of people! ! ! Who is who knows! ! ! The most comprehensive interview test mini program on the Internet, you can use your mobile phone to answer questions, take the subway, bus, and roll it up!

Covering these interview question sections:

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

How to obtain the full set of information: Click on the small card below to get it yourself