How to complete the automation framework? Python interface automation - data-driven combat, one article is enough...


foreword

In our test scenario, a login interface may have a dozen to dozens of test cases. If each set of data is written with a method, there will be more duplicate code, not only the execution efficiency is not high, but It is also not easy to maintain.

Next, we will optimize the framework and adopt a data-driven approach:
manage the test data with an excel sheet, and encapsulate the code;
use ddt to drive the test, and the two parts are independent of each other.

Introduction to the openpyxl module

openpyxl is a third-party module of python, which can read and write excel by using the openpyxl library.
Before understanding the openpyxl module, we need to be familiar with the structure of excel in order to better understand how openpyxl operates excel.

From the outside to the inside, the first is an excel file (name). After opening excel, you will see one or more sheets (workbooks) at the bottom. There are many cells in each sheet. Generally speaking, it is mainly divided into three levels.

B1

In opnepyxl, an Excel file corresponds to a Workbook object, a Sheet corresponds to a Worksheet object, and a cell corresponds to a Cell object. After understanding these, it is clearer how openpyxl operates excel.

openpyxl install

pip install openpyxl

openpyxl simple to use

import openpyxl

if __name__ == '__main__':
    path = 'F:/case/test_case.xlsx'
    # 读取excel文件
    workbook = openpyxl.load_workbook(path)
    # 读取所有sheet
    sheet = workbook.get_sheet_names()
    # 获取某个sheet
    sheet = workbook[sheet[0]]
    # 获取某个cell的值
    cell_val = sheet.cell(row=2, column=2).value
    print(cell_val)

Excel use case management

Under the project, create a new folder: data, and create a new cases.xlsx file under the folder to store test cases

B2

The following is a simple login test case design template:

B3

Actual results can be generated from this table and the test results written to the (Pass, Fail) table. Reply from the background of the official account: interface test case template, you can get the complete interface test case Excel template.

Now that we have a use case template, we start reading and writing data from excel with the openpyxl module. As follows, under the common folder, create a new excel_handle.py to encapsulate the class for operating excel.

B4

excel_handle.py

import openpyxl
class ExcelHandler:
    def __init__(self, file):
        self.file = file
    def open_excel(self, sheet_name):
        """打开Excel、获取sheet"""
        wb = openpyxl.load_workbook(self.file)
        # 获取sheet_name
        sheet = wb[sheet_name]
        return sheet
    def get_header(self, sheet_name):
        """获取header(表头)"""
        wb = self.open_excel(sheet_name)
        header = []
        # 遍历第一行
        for i in wb[1]:
            # 将遍历出来的表头字段加入列表
            header.append(i.value)
        return header
    def read_excel(self, sheet_name):
        """读取所有数据"""
        sheet = self.open_excel(sheet_name)
        rows = list(sheet.rows)
        data = []
        # 遍历从第二行开始的每一行数据
        for row in rows[1:]:
            row_data = []
            # 遍历每一行的每个单元格
            for cell in row:
                row_data.append(cell.value)
                # 通过zip函数将两个列表合并成字典
                data_dict = dict(zip(self.get_header(sheet_name),row_data))
            data.append(data_dict)
        return data
    @staticmethod
    def write_excel(file, sheet_name, row, cloumn,data):
        """Excel写入数据"""
        wb = openpyxl.load_workbook(file)
        sheet = wb[sheet_name]
        sheet.cell(row, cloumn).value = data
        wb.save(file)
        wb.close()
if __name__ == "__main__":
    # 以下为测试代码
    excel = ExcelHandler('../data/cases.xlsx')
    data = excel.read_excel('login')

DDT introduction and use

ddt introduction:
Name: Data-Driven Tests, data-driven testing
Function: The execution of test cases is driven by a collection of external data
Core idea: Data and test code separation
Application scenario: A set of external data to perform the same operation
Advantages: When testing In the case of a large number of data changes, the test code can remain unchanged
Actual project: excel stores test data, ddt reads test data to the unit test framework (in the test case)

Supplement:
The so-called data-driven refers to the change of data to drive the execution of automated tests, which ultimately leads to changes in test results. To put it bluntly, it is the application of parameterization.

ddt install:

pip install ddt

Use of ddt:
To know how to use ddt, we extract three important functions ddt, unpack, and data from the ddt module source code.

def ddt(cls):
    """
    Class decorator for subclasses of ``unittest.TestCase``.
    Apply this decorator to the test case class, and then
    decorate test methods with ``@data``.
    For each method decorated with ``@data``, this will effectively create as
    many methods as data items are passed as parameters to ``@data``.
    The names of the test methods follow the pattern
    ``original_test_name_{ordinal}_{data}``. ``ordinal`` is the position of the
    data argument, starting with 1.
    For data we use a string representation of the data value converted into a
    valid python identifier.  If ``data.__name__`` exists, we use that instead.
    For each method decorated with ``@file_data('test_data.json')``, the
    decorator will try to load the test_data.json file located relative
    to the python file containing the method that is decorated. It will,
    for each ``test_name`` key create as many methods in the list of values
    from the ``data`` key.
    """
    for name, func in list(cls.__dict__.items()):
        if hasattr(func, DATA_ATTR):
            for i, v in enumerate(getattr(func, DATA_ATTR)):
                test_name = mk_test_name(name, getattr(v, "__name__", v), i)
                test_data_docstring = _get_test_data_docstring(func, v)
                if hasattr(func, UNPACK_ATTR):
                    if isinstance(v, tuple) or isinstance(v, list):
                        add_test(
                            cls,
                            test_name,
                            test_data_docstring,
                            func,
                            *v
                        )
                    else:
                        # unpack dictionary
                        add_test(
                            cls,
                            test_name,
                            test_data_docstring,
                            func,
                            **v
                        )
                else:
                    add_test(cls, test_name, test_data_docstring, func, v)
            delattr(cls, name)
        elif hasattr(func, FILE_ATTR):
            file_attr = getattr(func, FILE_ATTR)
            process_file_data(cls, name, func, file_attr)
            delattr(cls, name)
    return cls
def unpack(func):
    """
    Method decorator to add unpack feature.
    """
    setattr(func, UNPACK_ATTR, True)
    return func
def data(*values):
    """
    Method decorator to add to your test methods.
    Should be added to methods of instances of ``unittest.TestCase``.
    """
    global index_len
    index_len = len(str(len(values)))
    return idata(values)

ddt:
Decoration class, which is a class inherited from TestCase.
data:
Decorate the test method. Parameters are a series of values.

unpack:
used when passing complex data structures. For example, if you use a tuple or a list, after adding unpack, ddt will automatically map the tuple or list to multiple parameters, and dictionaries can also be handled in this way; when unpack is not added, only one parameter of the method can be filled.

Example:
test_ddt.py

import unittest
import ddt
# 装饰类
@ddt.ddt
class DdtDemo(unittest.TestCase):
    def setUp(self):
        pass
    def tearDown(self):
        pass
    
    # 装饰方法
    @ddt.data(("15312344578", "12345678"), ("15387654321", "12345678"))
    @ddt.unpack
    def test_ddt(self, username,password):
        print(username,password)
if __name__ == '__main__':
    unittest.main(verbosity=2)

The result of the operation is:

Ran 2 tests in 0.001s
OK
15312344578 12345678
15387654321 12345678

test_login.py

import unittest
from common.requests_handler import RequestsHandler
from common.excel_handler import ExcelHandler
import ddt
import json
@ddt.ddt
class TestLogin(unittest.TestCase):
    # 读取excel中的数据
    excel = ExcelHandler('../data/cases.xlsx')
    case_data = excel.read_excel('login')
    print(case_data)
    def setUp(self):
        # 请求类实例化
        self.req = RequestsHandler()
    def tearDown(self):
        # 关闭session管理器
        self.req.close_session()
    @ddt.data(*case_data)
    def test_login_success(self,items):
        # 请求接口
        res = self.req.visit(method=items['method'],url=items['url'],json=json.loads(items['payload']),
                             headers=json.loads(items['headers']))
        try:
            # 断言:预期结果与实际结果对比
            self.assertEqual(res['code'], items['expected_result'])
            result = 'Pass'
        except AssertionError as e:
            result = 'Fail'
            raise e
        finally:
            # 将响应的状态码,写到excel的第9列,即写入返回的状态码
            TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 9, res['code'])
            # 如果断言成功,则在第10行(测试结果)写入Pass,否则,写入Fail
            TestLogin.excel.write_excel("../data/cases.xlsx", 'login', items['case_id'] + 1, 10, result)
if __name__ == '__main__':
    unittest.main()
The following is the most complete software test engineer learning knowledge architecture system diagram in 2023 that I compiled

1. From entry to mastery of Python programming

Please add a picture description

2. Interface automation project actual combat

Please add a picture description

3. Actual Combat of Web Automation Project

Please add a picture description

4. Actual Combat of App Automation Project

Please add a picture description

5. Resume of first-tier manufacturers

Please add a picture description

6. Test and develop DevOps system

Please add a picture description

7. Commonly used automated testing tools

Please add a picture description

Eight, JMeter performance test

Please add a picture description

9. Summary (little surprise at the end)

Don't stop, don't be afraid of failure, the road of struggle may be lonely and long, but persistence and hard work will light up the way forward. The realization of dreams requires sweat and tears. As long as the flame of passion is ignited in your heart, you can create your own brilliant life.

Go forward bravely, defy hardships, and the strength of struggle creates great achievements. Driven by passion, paved with hard work, the road to chasing dreams is never smooth, but every persistence will bring us one step closer to success.

No matter how decadent yesterday was, today is an opportunity to start over. Struggle is not only a process of hard work, but also the power to change destiny. Believe in your ability and persist in pursuit, only then can you bloom your own brilliance and create a proud life through hard work and sweat.

Guess you like

Origin blog.csdn.net/m0_70102063/article/details/132209665