简易selenium自动化测试框架(Python)

news2024/11/22 21:49:29
  •   📢专注于分享软件测试干货内容,欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
  • 📢交流讨论:欢迎加入我们一起学习!
  • 📢资源分享:耗时200+小时精选的「软件测试」资料包
  • 📢 最困难的时候,也就是我们离成功不远的时候!

最近空闲时间在探索Selenium的自动化测试,简单的写了一个小框架来测试公司的一个web产品。该框架包括以下模块:

1. Test case编写模式

2. Test case的管理及执行 (主要是用nose)

  该模块借助了一个外部txt文件来记录测试用例,每个用例为自身的文件名,如果不需要在本次执行,只需在文件名前添加一个“#”标识符就可以跳过该用例的执行。

3. 测试报告的生成(xml和html两种格式)

对于自动化测试而言,这些模块应该是最基本的配置了,当然还有一些辅助模块比如日志,其他公共库模块等需要根据具体的业务逐渐丰富。闲话少说,用代码交流吧。

测试用例编写

该模块用了Page模式,之前介绍过,这次只贴代码了

BasePage.py:

复制代码

__author__ = 'xua'

#super class
class BasePage(object):
    def __init__(self, driver):
        self.driver = driver

复制代码

然后是各个web page继承BasePage,LoginPage.py:

复制代码

from BasePage import BasePage
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys

class LoginPage(BasePage):
    """description of class"""

    #page element identifier
    usename = (By.ID,'username')
    password = (By.ID, 'password')
    dialogTitle = (By.XPATH,'//html/body/div[7]/div/div/div[1]/h3')
    cancelButton = (By.XPATH,'//html/body/div[7]/div/div/div[3]/button[2]')

    #Get username textbox and input username
    def set_username(self,username):
        name = self.driver.find_element(*LoginPage.usename)
        name.send_keys(username)
    
    #Get password textbox and input password, then hit return
    def set_password(self, password):
        pwd = self.driver.find_element(*LoginPage.password)
        pwd.send_keys(password + Keys.RETURN)

    #Get pop up dialog title
    def get_DiaglogTitle(self):
        digTitle = self.driver.find_element(*LoginPage.dialogTitle)
        return digTitle.text

    #Get "cancel" button and then click
    def click_cancel(self):
        cancelbtn = self.driver.find_element(*LoginPage.cancelButton)
        cancelbtn.click()

复制代码

测试用例信息类:

TestCaseInfo.py

复制代码

class TestCaseInfo(object):
    """description of class"""

    def __init__(self, id="",name="",owner="",result="Failed",starttime="",endtime="",errorinfo=""):
        self.id = id
        self.name = name
        self.owner = owner
        self.result = result
        self.starttime = starttime
        self.endtime = endtime
        self.errorinfo = errorinfo

复制代码

最后是每个测试用例的编写:(每个用例必须有自己的用例信息,这里有ID,Name等等信息,也会调用测试结果报告生成模块来添加测试结果)

Test_Login.py

复制代码

__author__ = 'xua'

from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.alert import Alert
import unittest
import time
from LoginPage import LoginPage
from TestCaseInfo import TestCaseInfo
from TestReport import TestReport

class Test_Login(unittest.TestCase):

    #Setup
    def setUp(self):
        self.driver = webdriver.Chrome(r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe')
        self.driver.implicitly_wait(30)
        self.base_url = "http://10.222.30.145:9000/"
        #test case information
        self.testcaseinfo = TestCaseInfo(id="3",name="Login to floor manager lite using sbxadmin",owner="xua")
        self.testResult = TestReport()
  
    def test_Login(self):
        try:
            self.testcaseinfo.starttime = str(time.asctime())
            #Step1: open base site
            self.driver.get(self.base_url)
            #Step2: Open Login page
            login_page = LoginPage(self.driver)
            #Step3: Enter username
            login_page.set_username("sbXadmin")
            #Step4: Enter password
            login_page.set_password("IGTtest1")
            #Checkpoint1: Check popup dialog title
            self.assertEqual(login_page.get_DiaglogTitle(),"Sign in","Not Equal")
            #Step5: Cancel dialog
            login_page.click_cancel()
            self.testcaseinfo.result = "Pass"
        except Exception as err:
            self.testcaseinfo.errorinfo = str(err)
        finally:
            self.testcaseinfo.endtime = str(time.asctime())

    #tearDown
    def tearDown(self):
        self.driver.close()
        #write test result
        self.testResult.WriteHTML(self.testcaseinfo)

if __name__ == "__main__":
    unittest.main()

复制代码

用例执行模块

1. 借助外部文件记录需要执行的用例

testcases.txt(带“#”标识的用例不会被执行):

Test_Login.py
Test_Login_2.py
#Test_Login_3.py
Test_Login_4.py

2. 利用nose的nosetests命令执行各个用例:

复制代码

import subprocess

class RunTests(object):
    """description of class"""
    def __init__(self):
        self.testcaselistfile = "testcases.txt"
    
    #use nosetests command to execute test case list
    def LoadAndRunTestCases(self):
        f = open(self.testcaselistfile)
        testfiles = [test for test in f.readlines() if not test.startswith("#")]
        f.close()
        for item in testfiles:
            subprocess.call("nosetests "+str(item).replace("\\n",""),shell = True)

if __name__ == "__main__":
    newrun = RunTests()
    newrun.LoadAndRunTestCases()

复制代码

测试结果报表生成模块

测试报表模块写了两种格式:xml和html

TestReport.py

复制代码

from xml.etree import ElementTree as ET
import os
import lxml.etree as mytree
from lxml import html

class TestReport(object):
    """description of class"""
    def __init__(self):
        self.testreport = "TestResult.xml"

    #If there is no "TestResult.xml", then create one
    def CreateTestResultFile(self):
        if os.path.exists(self.testreport) == False:
            newElem = ET.Element("TestCases")
            newTree = ET.ElementTree(newElem)
            newTree.write(self.testreport)
                        
    #Write test result to xml
    def WriteResult(self,testcaseInfo):
        self.CreateTestResultFile()
        testResultFile = ET.parse(self.testreport)
        root = testResultFile.getroot()
        newElem = ET.Element("TestCase")
        newElem.attrib = {
            "ID":testcaseInfo.id,
            "Name":testcaseInfo.name,
            "Owner":testcaseInfo.owner,
            "Result":testcaseInfo.result,
            "StartTime":testcaseInfo.starttime,
            "EndTime":testcaseInfo.endtime,
            "ErrorInfo":testcaseInfo.errorinfo
            }
        root.append(newElem)

        testResultFile.write(self.testreport)

    #If there is no "TestResult.html" file exists, then create one with default style
    def CreateHtmlFile(self):
        if os.path.exists("TestResult.html") == False:
            f = open("TestResult.html",'w')
            message = """<html>
            <head>    
                <title>Automation Test Result</title>
                <style>
                    table {
                            border-collapse: collapse;
                            padding: 15px;
                            font-family: "Trebuchet MS", Arial, Helvetica, sans-serif;
                            }
                    th{
                        background-color: green;
                        color: white;
                        border: 1px solid #ddd;
                        padding-bottom: 15px;
                        padding-top: 15px;
                    }
                    tr{
                        border: 1px solid #008000;
                        padding-bottom: 8px;
                        padding-top: 8px;
                        text-align: left;
                    }
                    td{
                        border: 1px solid #008000;
                    } 
                </style>
            </head>
            <body>
                <h1>Automation Test Result</h1>
                <table>
                    <tr>
                        <th>ID</th>
                        <th>Name</th>
                        <th>Owner</th>
                        <th>Result</th>
                        <th>StartTime</th>
                        <th>EndTime</th>
                        <th>ErrorMessage</th>
                   </tr>
                </table>
            </body>
            </html>
            """
            f.write(message)
            f.close()

    #append new test result to testresult file
    def WriteHTML(self,testcaseinfo):

        self.CreateHtmlFile()

        f = open("TestResult.html","r")
        
        htmlcontent = f.read()
        f.close()
        tree = html.fromstring(htmlcontent)
        tableElem = tree.find(".//table")
        if testcaseinfo.result == "Failed":
            mytablerow = "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td bgcolor=\"#FF0000\">{3}</td><td>{4}</td><td>{5}</td><td>{6}</td></tr>".format(testcaseinfo.id,testcaseinfo.name,testcaseinfo.owner,testcaseinfo.result,testcaseinfo.starttime,testcaseinfo.endtime,testcaseinfo.errorinfo)
        else:
            mytablerow = "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td><td>{6}</td></tr>".format(testcaseinfo.id,testcaseinfo.name,testcaseinfo.owner,testcaseinfo.result,testcaseinfo.starttime,testcaseinfo.endtime,testcaseinfo.errorinfo)
        tableElem.append(mytree.HTML(str(mytablerow)))

        f = open("TestResult.html","w")
        #html.tostring
        newContent = repr(html.tostring(tree,method="html",with_tail=False))
        newContent = newContent.replace(r"\n","").replace(r"\t","").replace('b\'',"")
        newContent = newContent[:len(newContent)-1]
        f.write(newContent)
        f.close()

复制代码

ok,最后看一下生成的测试报表:

总结 

在网上有很多关于Selenium自动化的Best Practice,当然大家也可以根据自己的需求来DIY自己的框架,不管简陋与否,好用才是硬道理:)!


行动吧,在路上总比一直观望的要好,未来的你肯定会感谢现在拼搏的自己!如果想学习提升找不到资料,没人答疑解惑时,请及时加入群,里面有各种测试开发资料和技术可以一起交流哦。

最后: 下方这份完整的软件测试视频教程已经整理上传完成,需要的朋友们可以自行领取 【保证100%免费】

软件测试面试文档

我们学习必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有字节大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1259062.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AIGC系列之:CLIP和OpenCLIP

目录 模型背景 CLIP模型介绍 相关资料 原理和方法 Image Encoder Text Encoder 对比学习 预训练 Zero Shot预测 优势和劣势 总结 OpenClip模型介绍 相关资料 原理 结果 用法 模型总结 模型背景 Stable Diffusion主要由三个核心模块组成&#xff1a; Text Enc…

聊聊如何进行代码混淆加固

​ 聊聊如何进行代码混淆 前言什么是代码混淆代码混淆&#xff0c;是指将计算机程序的代码&#xff0c;转换成一种功能上等价&#xff0c;但是难于阅读和理解的形式的行为。 代码混淆常见手段1、名称混淆 将有意义的类&#xff0c;字段、方法名称更改为无意义的字符串。生成…

多模态融合16篇优质论文及代码合集,含2023最新

多模态融合是多模态学习领域的基础问题&#xff0c;也是多模态研究中非常关键的研究点。它旨在从多个模态&#xff08;例如语音、图像、文本等&#xff09;中提取有价值的信息和特征&#xff0c;并将这些信息融合在一起以提高系统的性能。这一领域的研究内容广泛&#xff0c;包…

深入探索Maven:优雅构建Java项目的新方式(一)

Maven高级 1&#xff0c;分模块开发1.1 分模块开发设计1.2 分模块开发实现 2&#xff0c;依赖管理2.1 依赖传递与冲突问题2.2 可选依赖和排除依赖方案一:可选依赖方案二:排除依赖 3&#xff0c;聚合和继承3.1 聚合步骤1:创建一个空的maven项目步骤2:将项目的打包方式改为pom步骤…

CSGO搬砖还能做吗?CSGO饰品未来走势如何?

steam/csgo搬砖项目真能月入过万吗&#xff1f;到底真的假的&#xff1f; 如何看待CSGO饰品市场的整体走向&#xff1f; 从整体来说&#xff0c;CSGO的饰品市场与规模肯定会持续不断的上升&#xff0c;大盘不会发生特别大的波动&#xff0c;目前处于稳定期&#xff01;&…

05_属性描述符

05_属性描述符 文章目录 05_属性描述符一、属性描述符是什么&#xff1f;二、属性描述符①&#xff1a;查看属性描述②&#xff1a;设置属性描述符③&#xff1a;案例01.代码实现02.代码实现&#xff08;优化&#xff09; 一、属性描述符是什么&#xff1f; 属性描述符的结构 在…

Transformer中的多头注意力机制-为什么需要多头?

Transformer为什么使用多头注意力机制呢&#xff1f; 多头可以学习到不同维度的特征和信息。为什么可以学习到不同维度的信息呢&#xff1f; 答案是&#xff1a;多头注意力机制的组成是有单个的self attention&#xff0c;由于self attention通过产生QKV矩阵来学习数据特征&a…

字符串入门算法题!

概述 字符串和数组一样算是比较简单的题目&#xff0c;正适合打算法基础&#xff0c;一定要认真对待&#xff01;&#xff01;&#xff01; 字符串类型的算法问题可以分为简单、中等和困难的难度级别&#xff0c;基础类型一些基本的字符串处理问题&#xff0c;如字符串的拼接…

2023加拿大毕业典礼:共赴一场相遇 遥望未来可期

放眼国际金融&#xff0c;启幕璀璨时代。加拿大时间2023年11月14-16日&#xff0c;中国人民大学-加拿大女王大学金融硕士2023届行业高管班及国际班毕业生们携亲友&#xff0c;参加了为期3天的毕业庆祝活动&#xff0c;从加拿大女王大学史密斯商学院的多伦多教学区到女王大学的金…

随手写了个博客多平台发布脚本:Python自动发布文章到Wordpress

​ 引言 作为一名技术博主&#xff0c;提高博客发布效率是我们始终追求的目标。在这篇文章中&#xff0c;我将分享一个基于Python的脚本&#xff0c;能够实现博客多平台发布&#xff0c;具体来说&#xff0c;是自动发布文章到WordPress。通过这个简单而高效的脚本&#xff0c…

考试周刊杂志考试周刊杂志社考试周刊编辑部2023年第46期目录

教育教学研究 丰富作业形式 拓展课堂教学——“双减”下初中英语优化作业设计探析 王慧; 1-5 博学慎思明辨 撬动思维杠杆——论“思辨性阅读与表达”学习任务群范式构建 丁亚琴; 6-10《考试周刊》投稿邮箱&#xff1a;cn7kantougao163.com(注明投稿“《考试周刊》”) 崔…

折线图,样式调整background、serice、xAxis、yxAis等

效果展示&#xff1a; option参数&#xff1a; let option {backgroundColor: "rgba(48, 65, 90, 1)",title: {// text: obj.stnm,// subtext: obj.datasource,textStyle: {color: "#ffffff"},right: 10// left: center,// itemGap: 4},tooltip: {trigge…

JOSEF 综合继电器 HJZZ-32/2 AC220V 合闸延时整定0.02-9.99S

系列型号&#xff1a; HJZZ-91分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/1分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/2分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/2A分闸、合闸、电源监视综合装置&#xff1b; HJZZ-92/3分闸、合闸、电源监视综…

乐鑫推出 ESP ZeroCode ExL 模组

乐鑫推出 ESP ZeroCode ExL 模组&#xff0c;由 AWS IoT ExpressLink 提供支持&#xff0c;可简化用户构建兼容 Matter 的云连接设备。 为简化 Matter 设备的开发&#xff0c;乐鑫在年初发布了 ESP ZeroCode 模组和 ESP ZeroCode 控制台。ESP ZeroCode 模组非常适合一些简单设…

Gin框架如何使用并搭建一个后台管理系统 RBAC 权限管理(六)

一、RBAC 实现流程 1 、实现角色的增、删、改、查 2 、实现用户的增、删、改、查,增加修改用户的时候需要选择角色 3 、实现权限的增、删、改、查 (页面菜单) 4 、实现角色授权功能 5 、判断当前登录的用户是否有访问菜单的权限 6 、根据当前登录账户的角色信息动态显…

如何解决msvcp140.dll丢失问题,分享5个亲测有效的方法

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“msvcp140.dll丢失”。这个错误通常会导致某些应用程序无法正常运行。msvcp140.dll是Microsoft Visual C 2015 Redistributable Package的一部分&#xff0c;它是由Microsoft公司提供的运行…

seata集成springboot的一些错误小计

1 seata依赖没找到 dependencies.dependency.version for com.alibaba.cloud:spring-cloud-starter-alibaba-seata:jar is missing. line 126, column 21错误原因:未指定具体的seata版本 解决 <!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-st…

C语言:写一个函数,求字符串的长度,在main函数中输入字符串并输出其长度(指针)

分析&#xff1a; 在程序中&#xff0c;定义一个函数 fix&#xff0c;该函数使用指针变量来访问字符串中的每个字符&#xff0c;并计算出字符串的长度。fix 函数的参数为指向 char 类型的指针变量 p&#xff0c;表示需要计算长度的字符串。 在主函数 main 中&#xff0c;定义一…

全自动气象监测站天气预测的革新者

随着科技的不断进步&#xff0c;我们的生活变得越来越智能化。其中&#xff0c;WX-CQ12 全自动气象监测站以其精准的数据和实时的天气预报&#xff0c;成为了天气预测的革新者。本文将详细介绍全自动气象监测站的优势及其对人们生活的影响。 一、全自动气象监测站的优势 精准…

怎么把视频声音提取成MP3?一分钟解决!

有的时候&#xff0c;我们在看一些综艺访谈节目的时候&#xff0c;觉得里面干货满满&#xff0c;会忍不住想单独把音频下载出来单独听&#xff0c;还可以防止会员到期后不可以再播放&#xff0c;下面就向大家介绍三种好用的视频音乐提取成MP3的方法。 方法一&#xff1a;使用野…