Selenium+Pytest automated testing framework practice (Part 1)

Preface

Today, the author wants to talk to you about selenium automation + pytest testing framework. In this article, you need to know a certain python foundation - at least understand classes and objects, encapsulation inheritance; a certain selenium foundation. This article doesn't know selenium. If you don't, you can go to the selenium Chinese translation website.

1. Introduction to testing framework

What are the advantages of testing frameworks :

    • The code reuse rate is high. If you don’t use a framework, the code will be very redundant.
    • Can assemble some advanced functions such as logs, reports, emails, etc.
    • Improve the maintainability of data such as elements. When elements change, you only need to update the configuration file.
    • Use the more flexible PageObject design pattern
  • Overall directory of test frameworks
  • Directory/file description: Whether it is a python package common. This package stores common general classes. For example, reading the configuration file is config. The configuration file directory is logs log directory. Page deeply encapsulates selenium’s functions. It is page_element where page elements are stored. Directory page_object page object POM design pattern, TestCase all test case sets are utils tool classes are script script files conftest.pypytest glue file pytest.inipytest configuration file, such a simple framework structure is clear.

Now that we know the above, let’s get started!

In the project, we first build each directory according to the above framework guidelines.

Note: If you have a python package, you need to add an __init__.py file to identify this directory as a python package.

2. Management time

First of all, because many of our modules will use strings such as timestamps or dates, we first encapsulate the time into a module separately.

Then let other modules call it. Create a new times.py module in the utils directory

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import time
import datetime
from functools import wraps


def timestamp():
    """时间戳"""
    return time.time()


def dt_strftime(fmt="%Y%m"):
    """
    datetime格式化时间
    :param fmt "%Y%m%d %H%M%S
    """
    return datetime.datetime.now().strftime(fmt)


def sleep(seconds=1.0):
    """
    睡眠时间
    """
    time.sleep(seconds)


def running_time(func):
    """函数运行时间"""

    @wraps(func)
    def wrapper(*args, **kwargs):
        start = timestamp()
        res = func(*args, **kwargs)
        print("校验元素done!用时%.3f秒!" % (timestamp() - start))
        return res

    return wrapper


if __name__ == '__main__':
    print(dt_strftime("%Y%m%d%H%M%S"))

3. Add configuration file

Configuration files are an essential part of the project!

Concentrate fixed information in fixed files

3.1conf.py

There should be a file in the project to manage the overall directory. I also set this file in this python project.

Create a conf.py file in the project config directory, and all directory configuration information is written in this file.

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import os
from selenium.webdriver.common.by import By
from utils.times import dt_strftime


class ConfigManager(object):
    # 项目目录
    BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))

    # 页面元素目录
    ELEMENT_PATH = os.path.join(BASE_DIR, 'page_element')

    # 报告文件
    REPORT_FILE = os.path.join(BASE_DIR, 'report.html')

    # 元素定位的类型
    LOCATE_MODE = {
        'css': By.CSS_SELECTOR,
        'xpath': By.XPATH,
        'name': By.NAME,
        'id': By.ID,
        'class': By.CLASS_NAME
    }

    # 邮件信息
    EMAIL_INFO = {
        'username': '[email protected]',  # 切换成你自己的地址
        'password': 'QQ邮箱授权码',
        'smtp_host': 'smtp.qq.com',
        'smtp_port': 123
    }

    # 收件人
    ADDRESSEE = [
        '[email protected]',
    ]

    @property
    def log_file(self):
        """日志目录"""
        log_dir = os.path.join(self.BASE_DIR, 'logs')
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        return os.path.join(log_dir, '{}.log'.format(dt_strftime()))

    @property
    def ini_file(self):
        """配置文件"""
        ini_file = os.path.join(self.BASE_DIR, 'config', 'config.ini')
        if not os.path.exists(ini_file):
            raise FileNotFoundError("配置文件%s不存在!" % ini_file)
        return ini_file


cm = ConfigManager()
if __name__ == '__main__':
    print(cm.BASE_DIR)
Note: How to generate QQ mailbox authorization code and go to Baidu yourself
? I imitated the setting style of Django's settings.py file in this conf file, but there are some differences.

In this file we can set our own directories and view our current directory.

The convention is followed: constant names are all in uppercase, and function names are in lowercase. It looks overall beautiful.

3.2config.ini

Create a new config.ini file in the project config directory, and temporarily put the URL we need to test in it.

[HOST]
HOST = https://www.baidu.com

4. Read the configuration file

The configuration file has been created. Next we need to read the configuration file and use the information in it.

We create a new readconfig.py file in the common directory

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import configparser
from config.conf import cm

HOST = 'HOST'


class ReadConfig(object):
    """配置文件"""

    def __init__(self):
        self.config = configparser.RawConfigParser()  # 当有%的符号时请使用Raw读取
        self.config.read(cm.ini_file, encoding='utf-8')

    def _get(self, section, option):
        """获取"""
        return self.config.get(section, option)

    def _set(self, section, option, value):
        """更新"""
        self.config.set(section, option, value)
        with open(cm.ini_file, 'w') as f:
            self.config.write(f)

    @property
    def url(self):
        return self._get(HOST, HOST)


ini = ReadConfig()

if __name__ == '__main__':
    print(ini.url)

You can see that we used Python's built-in configparser module to read the config.ini file.

For extracting the url value, I used the high-level syntax @property attribute value, which is simpler to write.

5. Record operation logs

Log, everyone should be familiar with this term, which is to record the actions in the code.

Create a new logger.py file in the utils directory.

This file is used by us to record some operating steps during the automated testing process.

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import logging
from config.conf import cm


class Log:
    def __init__(self):
        self.logger = logging.getLogger()
        if not self.logger.handlers:
            self.logger.setLevel(logging.DEBUG)

            # 创建一个handle写入文件
            fh = logging.FileHandler(cm.log_file, encoding='utf-8')
            fh.setLevel(logging.INFO)

            # 创建一个handle输出到控制台
            ch = logging.StreamHandler()
            ch.setLevel(logging.INFO)

            # 定义输出的格式
            formatter = logging.Formatter(self.fmt)
            fh.setFormatter(formatter)
            ch.setFormatter(formatter)

            # 添加到handle
            self.logger.addHandler(fh)
            self.logger.addHandler(ch)

    @property
    def fmt(self):
        return '%(levelname)s\t%(asctime)s\t[%(filename)s:%(lineno)d]\t%(message)s'


log = Log().logger

if __name__ == '__main__':
    log.info('hello world')

Run the file in the terminal and see the command line print out:

INFO	2022-06-15 16:00:05,467	[logger.py:38]	hello world

Then the log file for the current month was generated in the project logs directory.

6. Simple understanding of POM model

Since we are going to talk about elements below, we first understand the POM model.

Page Object mode has the following advantages.

This view comes from "Selenium Automated Testing - Based on Python Language"
  • Abstracting the object can minimize the impact of developers modifying the page code on the test. Therefore, you only need to
    adjust the page object without affecting the test;
  • Part of the test code can be reused in multiple test cases;
  • Test code becomes more readable, flexible and maintainable

Page Object pattern diagram

 

  • basepage - the base class of selenium, which encapsulates selenium methods
  • pageelements - page elements, extract page elements individually and put them into a file
  • searchpage - page object class, integrating selenium methods and page elements
  • testcase - use pytest to write test cases for the integrated searchpage

From the above figure we can see that through the POM model idea, we put:

  • selenium methods
  • page elements
  • page object
  • test case

The above four code bodies are split. Although it will increase the code when there are few use cases, it is very meaningful when there are many use cases. The amount of code will be significantly reduced when the use cases increase. Our code maintenance has become more intuitive and obvious, the code readability has become much better than the factory mode, and the code reuse rate has also been greatly improved.

Finally: The following are supporting learning materials. For those who are doing [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!

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!

Covers the following 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

Guess you like

Origin blog.csdn.net/weixin_57794111/article/details/132918077