自动化测试(web测试selenium框架)

什么是selenium?javascript

一个用于Web应用程序测试的工具直接运行在浏览器中,就像真正的用户在操做同样。支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。测试与浏览器的兼容性,测试你的应用程序看是否可以很好得工做在不一样浏览器和操做系统之上。测试系统功能,建立衰退测试检验软件功能和用户需求。php

slenium前世css

早期是直接使用 javascrip 注入技术与浏览器打交道,slenium RC启动一个server 将web元素api转换为javascript。在Selenium内核启动浏览器以后注入这段Javascript,由此才实现了Selenium的目的:自动化Web操做。这种Javascript注入技术的缺点是速度不理想,并且稳定性大大依赖于Selenium内核对API翻译成的Javascript质量高低。html

slenium如今前端

Selenium2.x 提出了WebDriver的概念以后与浏览器交互利用原生的API,直接操做浏览器页面里的元素。不一样的浏览器厂商对Web元素的操做和呈现一些差别直接致使了Selenium WebDriver要分浏览器厂商不一样,而提供不一样的实现。Selenium3.0发布后,最大更新点就是干掉了对selenium rc的支持,后面就一直是webdriver协议,java

WebDriver工做流程python

一、经过WebDriver建立一个浏览器服务,remote server
二、脚本启动时会在新的线程中启动一个浏览器,并绑定特定的端口,没个浏览器有不一样的端口段。
三、client 建立1个session,在该session中经过http请求向remote server发送restful的请求,remote server解析请求,完成相应操做并返回response。
四、分析response,继续执行脚本仍是结束执行
command.py:Command类中定义了WebDriver的一些经常使用的常量。git

remote\webdrvier.py:全部浏览器webdrvier的基类,其中包含了全部webdriver的api接口github

remote\remote_connection.py:包含启动Remote WebDrvier server,执行client请求,self._commands是selenium的核心请求参数,根据对应的Command常量,发送不一样的http请求。web

selenium 中的等待方式:time(固定等待),implicitly_wait(隐式等待),WebDriverWait(显示等待)

webdriver client的原理

当测试脚本启动Chrome的时候,selenium-webdriver 会首先在新线程中启动Chrome浏览器。启动后selenium-webdriver会将Chrome绑定到特定的端口,绑定完成后该chrome实例便做为webdriver的remote server存在;客户端(也就是测试脚本)建立1个会话,在该session中经过http请求向remote server发送请求,remote server解析请求,完成相应操做并返回response;客户端接受response,并分析其返回值以决定是转到第3步仍是结束脚本;

webdriver是按照server – client的经典设计模式设计的。

server端就是remote server,能够是任意的浏览器。当咱们的脚本启动浏览器后,该浏览器就是remote server,它的职责就是等待client(脚本)发送请求并作出相应;

client端简单说来就是咱们的测试代码,咱们测试代码中的一些行为,好比打开浏览器,转跳到特定的url等操做是以http请求的方式发送给被测试浏览器,也就是remote server;remote server接受请求,并执行相应操做,并在response中返回执行状态、返回值等信息;

selenium的搭建
1.在python中安装好selenium包 : pip install selenium

2.在配置好浏览器的驱动程序根据http://www.imdsx.cn/index.php/2017/08/02/drvier/ 驱动对照表下载Chrome对驱动,并添加在PATH环境变量中,(或者直接把驱动放在pytho的安装目录下)

 Firefox驱动下载地址为:https://github.com/mozilla/geckodriver/releases/       ,

 IE浏览器驱动下载地址为:http://selenium-release.storage.googleapis.com/index.html

编写如下代码能打开对应的浏览器就配置成功:

from selenium import webdriver
driver = webdriver.Chrome()
driver.get('http://www.imdsx.cn')
google浏览器
from selenium import webdriver
driver = webdriver.Firefox()
driver.get('http://www.imdsx.cn')
火狐浏览器
from selenium import webdriver
driver = webdriver.Ie()
driver.get('http://www.imdsx.cn')
IE浏览器

 selenium定位

import selenium #引用selenium包
from selenium import webdriver#引用包的服务
driver = webdriver.Chrome()#建立浏览器 当作咱们的服务端
driver.get('xxxxxxxxxxxxxxx/')#打开对应测试网站,这里的url 必须带有http
# 8种单数定位方式
# id进行定位
# driver.find_element_by_id('i1').send_keys('123123')#send_keys向文本框输入数字
# class 定位方式
# driver.find_element_by_class_name('classname').send_keys('123123')
# name定位方式
# driver.find_element_by_name('name').send_keys('123123')
# 文案定位
# driver.find_element_by_link_text('新建标签页面').click()  #.click()表示点击操做
# 文案包含定位方式
js = 'window.scrollTo(0,0);' # 将滚动条调制最上方
driver.execute_script(js)# 执行写好的js
# import time
# # time.sleep(2)#界面若是反应比较慢能够加载等等时间
# driver.find_element_by_partial_link_text('新建标签').click()
# 标签名定位 最不经常使用的
# driver.find_element_by_tag_name('input').send_keys('1111')
# xpath 定位
# driver.find_element_by_xpath('//*[@id="i1"]').send_keys('2222')
# css id  定位
# driver.find_element_by_css_selector('#i1').send_keys('2222')
# # css name  定位
# driver.find_element_by_css_selector('name').send_keys()
8种定位方式
xpath定位
xpath(xpath 定位尽可能少用层级定位,若是开发更改了页面的层级,全部定位都挂了,尽可能属性定位为主,层级为辅助)
        //* 取当前页面的所有元素
        //*[@id='i1'] id 进行定位 @表明引用属性
        //*[@placeholder="请经过ID定位元素"] 
        //input[@placeholder="请经过ID定位元素"] 经过 标签名进一步缩小范围
        //select[4] 若是存在不惟一的状况 能够经过角标进行取值 xpath从1开始取
        //select[@size="4" and @multiple="multiple"]  逻辑定位
xpath定位

当不肯定时能够只用copy直接复制xpath地址(这个地址至关于层级定位最好少用)

 

css selector定位
css  selector
1.支持ID,class 定位  (# 表明id)  ( . 表示class)
不是说不能用class 若是class属性在页面中惟一,那么是能够等同于id来使用

2.属性定位
[placeholder = "请经过ID定位元素"]  属性定位

3.标签组合定位
input[placeholder = "请经过ID定位元素"] 缩小范围 先定位input 在定位属性

4.多属性组合定位
Css Selector 的多属性组合选择过滤 没有and 只须要多个[] 链接 就能够
select[size = "4"][multiple = "multiple"] 多属性确立惟一

5.层级关系定位
经过  >  来区分层级的界定
select>option[value='3']

6.模糊匹配
^= 匹配元素属性以什么开头
input[value ^= ""]
$= 匹配属性以什么结尾
input[value$=""]
*= 匹配属性包含什么值 input
[value *= ""]
View Code
 

作UI自动化前须要了解什么

1.何时作UI自动化:当项目已经稳定不在大面积修改的状况下,就能够接自动化了。

2.作UI自动化须要了解什么知识:前端HTML,CSS,定位方式

 简单的UI自动化框架

1.bin 目录下放程序入口
2.lib 目录下放一些配置文件
3.log 目录下放日志
  (HTMLTestRunne :生产网页的报告页面,
    logger 生成日志
    path  配置地址
    pyse 定位页元素使用的框架
    tool  生成错误图片)
4.pages 目录下放页面元素、
5.report  目录下放文件运行报告  (picture)下放错误截图
6.test_case 目录下放用例

框架能实现:
1、基于显示等待 解决不稳定的状况
(time:固定等待 , implicitly_wait: 隐式等待,webDriveWait:显示等待)
2.解决维护麻烦 PO(page object)思想(以一个页面当作一个类,每个页面的功能点当作一个函数)
3.自动化测试用例和页面数据源进行分离。

怎么判断业务逻辑的成功
举例说明:假设是登陆的业务逻辑,判断登陆的特有元素消失 ,就表明登陆成功了。
只有登陆成功了才会出现的元素 判断一下他是否出现
文档说明
from lib.logger import logger
from lib.path import WEBCASEPATH,REPORTPATH
from lib.HTMLTestRunner import HTMLTestRunner
import unittest
from lib.tool import Tool

class Main(object):
    def run(self):
        Tool().clear_picture()
        suite = unittest.TestSuite()
        cases = unittest.defaultTestLoader.discover(WEBCASEPATH)
        print(cases)
        for case in cases:
            print(case)
            suite.addTest(case)
        f = open(REPORTPATH,'wb')
        runner = HTMLTestRunner(f,verbosity=1,title=u'测试报告', description=u'用例执行状况:')
        runner.run(suite)
        f.flush()
        f.close()
if __name__ == '__main__':
    Main().run()
main
# -*- coding: utf-8 -*-
"""
A TestRunner for use with the Python unit testing framework. It
generates a HTML report to show the result at a glance.

The simplest way to use this is to invoke its main method. E.g.

    import unittest
    import HTMLTestRunner

    ... define your tests ...

    if __name__ == '__main__':
        HTMLTestRunner.main()


For more customization options, instantiates a HTMLTestRunner object.
HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g.

    # output to a file
    fp = file('my_report.html', 'wb')
    runner = HTMLTestRunner.HTMLTestRunner(
                stream=fp,
                title='My unit test',
                description='This demonstrates the report output by HTMLTestRunner.'
                )

    # Use an external stylesheet.
    # See the Template_mixin class for more customizable options
    runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">'

    # run the test
    runner.run(my_test_suite)


------------------------------------------------------------------------
Copyright (c) 2004-2007, Wai Yip Tung
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

* Redistributions of source code must retain the above copyright notice,
  this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
  notice, this list of conditions and the following disclaimer in the
  documentation and/or other materials provided with the distribution.
* Neither the name Wai Yip Tung nor the names of its contributors may be
  used to endorse or promote products derived from this software without
  specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""

# URL: http://tungwaiyip.info/software/HTMLTestRunner.html

__author__ = "Wai Yip Tung"
__version__ = "0.8.3"

"""
Change History
Version 0.8.3
* Use Bootstrap (Zhang Xin)
* Change to Chinese (Zhang Xin)

Version 0.8.2
* Show output inline instead of popup window (Viorel Lupu).

Version in 0.8.1
* Validated XHTML (Wolfgang Borgert).
* Added description of test classes and test cases.

Version in 0.8.0
* Define Template_mixin class for customization.
* Workaround a IE 6 bug that it does not treat <script> block as CDATA.

Version in 0.7.1
* Back port to Python 2.3 (Frank Horowitz).
* Fix missing scroll bars in detail log (Podi).
"""

# TODO: color stderr
# TODO: simplify javascript using ,ore than 1 class in the class attribute?

import datetime
import io
import sys
import time
import unittest
from xml.sax import saxutils


# ------------------------------------------------------------------------
# The redirectors below are used to capture output during testing. Output
# sent to sys.stdout and sys.stderr are automatically captured. However
# in some cases sys.stdout is already cached before HTMLTestRunner is
# invoked (e.g. calling logging.basicConfig). In order to capture those
# output, use the redirectors for the cached stream.
#
# e.g.
#   >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector)
#   >>>

class OutputRedirector(object):
    """ Wrapper to redirect stdout or stderr """

    def __init__(self, fp):
        self.fp = fp

    def write(self, s):
        self.fp.write(s)

    def writelines(self, lines):
        self.fp.writelines(lines)

    def flush(self):
        self.fp.flush()


stdout_redirector = OutputRedirector(sys.stdout)
stderr_redirector = OutputRedirector(sys.stderr)


# ----------------------------------------------------------------------
# Template

class Template_mixin(object):
    """
    Define a HTML template for report customerization and generation.

    Overall structure of an HTML report

    HTML
    +------------------------+
    |<html>                  |
    |  <head>                |
    |                        |
    |   STYLESHEET           |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |  </head>               |
    |                        |
    |  <body>                |
    |                        |
    |   HEADING              |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   REPORT               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |   ENDING               |
    |   +----------------+   |
    |   |                |   |
    |   +----------------+   |
    |                        |
    |  </body>               |
    |</html>                 |
    +------------------------+
    """

    STATUS = {
        0: u'经过',
        1: u'失败',
        2: u'错误',
    }

    DEFAULT_TITLE = 'Unit Test Report'
    DEFAULT_DESCRIPTION = ''

    # ------------------------------------------------------------------------
    # HTML Template

    HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>%(title)s</title>
    <meta name="generator" content="%(generator)s"/>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    %(stylesheet)s
    <link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet">

</head>
<body>
<script language="javascript" type="text/javascript"><!--
output_list = Array();

/* level - 0:Summary; 1:Failed; 2:All */
function showCase(level) {
    trs = document.getElementsByTagName("tr");
    for (var i = 0; i < trs.length; i++) {
        tr = trs[i];
        id = tr.id;
        if (id.substr(0,2) == 'ft') {
            if (level < 1) {
                tr.className = 'hiddenRow';
            }
            else {
                tr.className = '';
            }
        }
        if (id.substr(0,2) == 'pt') {
            if (level > 1) {
                tr.className = '';
            }
            else {
                tr.className = 'hiddenRow';
            }
        }
    }
}


function showClassDetail(cid, count) {
    var id_list = Array(count);
    var toHide = 1;
    for (var i = 0; i < count; i++) {
        tid0 = 't' + cid.substr(1) + '.' + (i+1);
        tid = 'f' + tid0;
        tr = document.getElementById(tid);
        if (!tr) {
            tid = 'p' + tid0;
            tr = document.getElementById(tid);
        }
        id_list[i] = tid;
        if (tr.className) {
            toHide = 0;
        }
    }
    for (var i = 0; i < count; i++) {
        tid = id_list[i];
        if (toHide) {
            if(document.getElementById('div_'+tid) == null){
                document.getElementById(tid).className = 'hiddenRow';
            }else{
                document.getElementById('div_'+tid).style.display = 'none'
                document.getElementById(tid).className = 'hiddenRow';
            }

        }
        else {
            document.getElementById(tid).className = '';
        }
    }
}


function showTestDetail(div_id){
    var details_div = document.getElementById(div_id)
    var displayState = details_div.style.display
    // alert(displayState)
    if (displayState != 'block' ) {
        displayState = 'block'
        details_div.style.display = 'block'
    }
    else {
        details_div.style.display = 'none'
    }
}


function html_escape(s) {
    s = s.replace(/&/g,'&amp;');
    s = s.replace(/</g,'&lt;');
    s = s.replace(/>/g,'&gt;');
    return s;
}

/* obsoleted by detail in <div>
function showOutput(id, name) {
    var w = window.open("", //url
                    name,
                    "resizable,scrollbars,status,width=800,height=450");
    d = w.document;
    d.write("<pre>");
    d.write(html_escape(output_list[id]));
    d.write("\n");
    d.write("<a href='javascript:window.close()'>close</a>\n");
    d.write("</pre>\n");
    d.close();
}
*/
--></script>
<div id="div_base">

%(heading)s
%(report)s
%(ending)s

</div>
</body>
</html>
"""
    # variables: (title, generator, stylesheet, heading, report, ending)


    # ------------------------------------------------------------------------
    # Stylesheet
    #
    # alternatively use a <link> for external style sheet, e.g.
    #   <link rel="stylesheet" href="$url" type="text/css">

    STYLESHEET_TMPL = """
<style type="text/css" media="screen">
body        { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; }
table       { font-size: 100%; }
pre         { white-space: pre-wrap;word-wrap: break-word; }

/* -- heading ---------------------------------------------------------------------- */
h1 {
    font-size: 16pt;
    color: gray;
}
.heading {
    margin-top: 0ex;
    margin-bottom: 1ex;
}

.heading .attribute {
    margin-top: 1ex;
    margin-bottom: 0;
}

.heading .description {
    margin-top: 2ex;
    margin-bottom: 3ex;
}

/* -- css div popup ------------------------------------------------------------------------ */
a.popup_link {
}

a.popup_link:hover {
    color: red;
}

.popup_window {
    display: none;
    position: relative;
    left: 0px;
    top: 0px;
    /*border: solid #627173 1px; */
    padding: 10px;
    background-color: #E6E6D6;
    font-family: "Lucida Console", "Courier New", Courier, monospace;
    text-align: left;
    font-size: 8pt;
    /* width: 500px;*/
}

}
/* -- report ------------------------------------------------------------------------ */
#show_detail_line {
    margin-top: 3ex;
    margin-bottom: 1ex;
}
#result_table {
    width: 99%;
}
#header_row {
    font-weight: bold;
    color: white;
    background-color: #777;
}
#total_row  { font-weight: bold; }
.passClass  { background-color: #74A474; }
.failClass  { background-color: #FDD283; }
.errorClass { background-color: #FF6600; }
.passCase   { color: #6c6; }
.failCase   { color: #FF6600; font-weight: bold; }
.errorCase  { color: #c00; font-weight: bold; }
.hiddenRow  { display: none; }
.testcase   { margin-left: 2em; }


/* -- ending ---------------------------------------------------------------------- */
#ending {
}

#div_base {
            position:absolute;
            top:0%;
            left:5%;
            right:5%;
            width: auto;
            height: auto;
            margin: -15px 0 0 0;
}
</style>
"""

    # ------------------------------------------------------------------------
    # Heading
    #

    HEADING_TMPL = """<div class='page-header' style='margin-top: 15px;'>
<h1>%(title)s</h1>
%(parameters)s
</div>
<p class='description'>%(description)s</p>

"""  # variables: (title, parameters, description)

    HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p>
"""  # variables: (name, value)

    # ------------------------------------------------------------------------
    # Report
    #

    REPORT_TMPL = u"""
<div class="btn-group btn-group-sm">
<button class="btn btn-default" onclick='javascript:showCase(0)'>总结</button>
<button class="btn btn-default" onclick='javascript:showCase(1)'>失败</button>
<button class="btn btn-default" onclick='javascript:showCase(2)'>所有</button>
</div>
<p></p>
<table id='result_table' class="table table-bordered">
<colgroup>
<col align='left' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
<col align='right' />
</colgroup>
<tr id='header_row'>
    <td>测试套件/测试用例</td>
    <td>总数</td>
    <td>经过</td>
    <td>失败</td>
    <td>错误</td>
    <td>查看</td>
</tr>
%(test_list)s
<tr id='total_row'>
    <td>总计</td>
    <td>%(count)s</td>
    <td>%(Pass)s</td>
    <td>%(fail)s</td>
    <td>%(error)s</td>
    <td>&nbsp;</td>
</tr>
</table>
"""  # variables: (test_list, count, Pass, fail, error)

    REPORT_CLASS_TMPL = u"""
<tr class='%(style)s'>
    <td>%(desc)s</td>
    <td>%(count)s</td>
    <td>%(Pass)s</td>
    <td>%(fail)s</td>
    <td>%(error)s</td>
    <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">详情</a></td>
</tr>
"""  # variables: (style, desc, count, Pass, fail, error, cid)

    REPORT_TEST_WITH_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'>
    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
    <td colspan='5' align='center'>

    <!--css div popup start-->
    <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" >
        %(status)s</a>

    <div id='div_%(tid)s' class="popup_window">
        <div style='text-align: right; color:red;cursor:pointer;height: 200px;position: relative;'>
        <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " >
           [x]</a>
        </div>
        %(script)s
<a href="#" onclick="window.open('picture/%(png)s','','WIDTH=1034,height=619 TOP=0 left=200')"><IMG SRC=picture/%(png)s style="width: 390px;height: 200px;position: absolute;top: 10px;left: 135px"></a>
    </div>
    <!--css div popup end-->

    </td>
</tr>
"""  # variables: (tid, Class, style, desc, status)

    REPORT_TEST_NO_OUTPUT_TMPL = r"""
<tr id='%(tid)s' class='%(Class)s'>
    <td class='%(style)s'><div class='testcase'>%(desc)s</div></td>
    <td colspan='5' align='center'>%(status)s</td>
</tr>
"""  # variables: (tid, Class, style, desc, status)

    REPORT_TEST_OUTPUT_TMPL = r"""
%(id)s: %(output)s
"""  # variables: (id, output)

    # ------------------------------------------------------------------------
    # ENDING
    #

    ENDING_TMPL = """<div id='ending'>&nbsp;</div>"""


# -------------------- The end of the Template class -------------------


TestResult = unittest.TestResult


class _TestResult(TestResult):
    # note: _TestResult is a pure representation of results.
    # It lacks the output and reporting ability compares to unittest._TextTestResult.

    def __init__(self, verbosity=1):
        TestResult.__init__(self)
        self.stdout0 = None
        self.stderr0 = None
        self.success_count = 0
        self.failure_count = 0
        self.error_count = 0
        self.verbosity = verbosity

        # result is a list of result in 4 tuple
        # (
        #   result code (0: success; 1: fail; 2: error),
        #   TestCase object,
        #   Test output (byte string),
        #   stack trace,
        # )
        self.result = []

    def startTest(self, test):
        TestResult.startTest(self, test)
        # just one buffer for both stdout and stderr
        self.outputBuffer = io.StringIO()
        stdout_redirector.fp = self.outputBuffer
        stderr_redirector.fp = self.outputBuffer
        self.stdout0 = sys.stdout
        self.stderr0 = sys.stderr
        sys.stdout = stdout_redirector
        sys.stderr = stderr_redirector

    def complete_output(self):
        """
        Disconnect output redirection and return buffer.
        Safe to call multiple times.
        """
        if self.stdout0:
            sys.stdout = self.stdout0
            sys.stderr = self.stderr0
            self.stdout0 = None
            self.stderr0 = None
        return self.outputBuffer.getvalue()

    def stopTest(self, test):
        # Usually one of addSuccess, addError or addFailure would have been called.
        # But there are some path in unittest that would bypass this.
        # We must disconnect stdout in stopTest(), which is guaranteed to be called.
        self.complete_output()

    def addSuccess(self, test):
        self.success_count += 1
        TestResult.addSuccess(self, test)
        output = self.complete_output()
        self.result.append((0, test, output, ''))
        if self.verbosity > 1:
            sys.stderr.write('ok ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('.')

    def addError(self, test, err):
        self.error_count += 1
        TestResult.addError(self, test, err)
        _, _exc_str = self.errors[-1]
        output = self.complete_output()
        self.result.append((2, test, output, _exc_str))
        if self.verbosity > 1:
            sys.stderr.write('E  ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('E')

    def addFailure(self, test, err):
        self.failure_count += 1
        TestResult.addFailure(self, test, err)
        _, _exc_str = self.failures[-1]
        output = self.complete_output()
        self.result.append((1, test, output, _exc_str))
        if self.verbosity > 1:
            sys.stderr.write('F  ')
            sys.stderr.write(str(test))
            sys.stderr.write('\n')
        else:
            sys.stderr.write('F')


from lib.logger import logger


class HTMLTestRunner(Template_mixin):
    """
    """

    def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None):
        self.stream = stream
        self.verbosity = verbosity
        if title is None:
            self.title = self.DEFAULT_TITLE
        else:
            self.title = title
        if description is None:
            self.description = self.DEFAULT_DESCRIPTION
        else:
            self.description = description

        self.startTime = datetime.datetime.now()

    def run(self, test):
        "Run the given test case or test suite."
        result = _TestResult(self.verbosity)
        test(result)
        self.stopTime = datetime.datetime.now()
        self.generateReport(test, result)
        # print >>sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)
        return result

    def sortResult(self, result_list):
        # unittest does not seems to run in any particular order.
        # Here at least we want to group them together by class.
        rmap = {}
        classes = []
        for n, t, o, e in result_list:
            cls = t.__class__
            if not cls in rmap:
                rmap[cls] = []
                classes.append(cls)
            rmap[cls].append((n, t, o, e,))
        r = [(cls, rmap[cls]) for cls in classes]
        return r

    def getReportAttributes(self, result):
        """
        Return report attributes as a list of (name, value).
        Override this to add custom attributes.
        """
        startTime = str(self.startTime)[:19]
        if hasattr(self, 'self.stopTime'):
            duration = str(self.stopTime - self.startTime)
        else:
            self.stopTime = datetime.datetime.now()
            duration = str(self.stopTime - self.startTime)
        status = []
        if result.success_count: status.append(u'经过 %s' % result.success_count)
        if result.failure_count: status.append(u'失败 %s' % result.failure_count)
        if result.error_count:   status.append(u'错误 %s' % result.error_count)
        if status:
            status = ' '.join(status)
        else:
            status = 'none'
        return [
            (u'开始时间', startTime),
            (u'运行时长', duration),
            (u'状态', status),
        ]

    def generateReport(self, test, result):
        report_attrs = self.getReportAttributes(result)
        generator = 'HTMLTestRunner %s' % __version__
        stylesheet = self._generate_stylesheet()
        heading = self._generate_heading(report_attrs)
        report = self._generate_report(result)
        ending = self._generate_ending()
        output = self.HTML_TMPL % dict(
            title=saxutils.escape(self.title),
            generator=generator,
            stylesheet=stylesheet,
            heading=heading,
            report=report,
            ending=ending,
        )
        self.stream.write(output.encode('utf8'))

    def _generate_stylesheet(self):
        return self.STYLESHEET_TMPL

    def _generate_heading(self, report_attrs):
        a_lines = []
        for name, value in report_attrs:
            line = self.HEADING_ATTRIBUTE_TMPL % dict(
                name=saxutils.escape(name),
                value=saxutils.escape(value),
            )
            a_lines.append(line)
        heading = self.HEADING_TMPL % dict(
            title=saxutils.escape(self.title),
            parameters=''.join(a_lines),
            description=saxutils.escape(self.description),
        )
        return heading

    def _generate_report(self, result):
        rows = []
        sortedResult = self.sortResult(result.result)
        for cid, (cls, cls_results) in enumerate(sortedResult):
            # subtotal for a class
            np = nf = ne = 0
            for n, t, o, e in cls_results:
                if n == 0:
                    np += 1
                elif n == 1:
                    nf += 1
                else:
                    ne += 1

            # format class description
            if cls.__module__ == "__main__":
                name = cls.__name__
            else:
                name = "%s.%s" % (cls.__module__, cls.__name__)
            doc = cls.__doc__ and cls.__doc__.split("\n")[0] or ""
            desc = doc and '%s: %s' % (name, doc) or name

            row = self.REPORT_CLASS_TMPL % dict(
                style=ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass',
                desc=desc,
                count=np + nf + ne,
                Pass=np,
                fail=nf,
                error=ne,
                cid='c%s' % (cid + 1),
            )
            rows.append(row)
            from lib.tool import Tool
            pnglist = Tool().error_picture()
            logger.debug(pnglist)
            if len(pnglist) > 0:
                Rewrite_results = []
                for cls_p in cls_results:
                    name = cls_p[1].id().split('.')[-1]
                    for png in pnglist:
                        png_name = png[0].split('.')[0]
                        if png_name == name:
                            tmp = cls_p + png
                            Rewrite_results.append(tmp)
                            break
                    else:
                        tmp = cls_p + ('',)
                        Rewrite_results.append(tmp)
                for tid, (n, t, o, e, png) in enumerate(Rewrite_results):
                    self._generate_report_test(rows, cid, tid, n, t, o, e, png)
            else:
                for tid, (n, t, o, e) in enumerate(cls_results):
                    self._generate_report_test(rows, cid, tid, n, t, o, e)

        report = self.REPORT_TMPL % dict(
            test_list=''.join(rows),
            count=str(result.success_count + result.failure_count + result.error_count),
            Pass=str(result.success_count),
            fail=str(result.failure_count),
            error=str(result.error_count),
        )
        return report

    def _generate_report_test(self, rows, cid, tid, n, t, o, e, png=''):
        # e.g. 'pt1.1', 'ft1.1', etc
        has_output = bool(o or e)
        tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid + 1, tid + 1)
        name = t.id().split('.')[-1]
        doc = t.shortDescription() or ""
        desc = doc and ('%s: %s' % (name, doc)) or name
        tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL

        # o and e should be byte string because they are collected from stdout and stderr?
        if isinstance(o, str):
            # TODO: some problem with 'string_escape': it escape \n and mess up formating
            # uo = unicode(o.encode('string_escape'))
            uo = o
        else:
            uo = o
        if isinstance(e, str):
            # TODO: some problem with 'string_escape': it escape \n and mess up formating
            # ue = unicode(e.encode('string_escape'))
            ue = e
        else:
            ue = e
        if png:
            script = ''
        else:
            script = self.REPORT_TEST_OUTPUT_TMPL % dict(
                id=tid,
                output=saxutils.escape(uo + ue),
            )

        row = tmpl % dict(
            tid=tid,
            Class=(n == 0 and 'hiddenRow' or 'none'),
            style=n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'),
            desc=desc,
            script=script,
            png=png,
            status=self.STATUS[n],
        )
        rows.append(row)
        if not has_output:
            return

    def _generate_ending(self):
        return self.ENDING_TMPL


##############################################################################
# Facilities for running tests from the command line
##############################################################################

# Note: Reuse unittest.TestProgram to launch test. In the future we may
# build our own launcher to support more specific command line
# parameters like test title, CSS, etc.
class TestProgram(unittest.TestProgram):
    """
    A variation of the unittest.TestProgram. Please refer to the base
    class for command line parameters.
    """

    def runTests(self):
        # Pick HTMLTestRunner as the default test runner.
        # base class's testRunner parameter is not useful because it means
        # we have to instantiate HTMLTestRunner before we know self.verbosity.
        if self.testRunner is None:
            self.testRunner = HTMLTestRunner(verbosity=self.verbosity)
        unittest.TestProgram.runTests(self)


main = TestProgram

##############################################################################
# Executing this module from the command line
##############################################################################

if __name__ == "__main__":
    main(module=None)
HTMLTestRunner
from logging import handlers
import logging
from lib.path import WEBLOGPATH


class Logger(object):
    __instance = None

    def __new__(cls, *args, **kwargs):
        if not Logger.__instance:
            Logger.__instance = object.__new__(cls, *args)
        return Logger.__instance

    def __init__(self):
        # 格式化log的模板
        self.formater = logging.Formatter(
            '[%(asctime)s] [%(levelname)s] [%(filename)s:%(funcName)s:%(lineno)d] %(message)s')

        # 声明一个log对象
        self.logger = logging.getLogger('log')
        # 设置全局log级别
        self.logger.setLevel(logging.DEBUG)

        # 文件log
        self.filelogger = handlers.RotatingFileHandler(WEBLOGPATH,
                                                       maxBytes=5242880,
                                                       backupCount=3
                                                       )
        # 屏幕log
        self.console = logging.StreamHandler()
        # 对屏幕设置级别
        self.console.setLevel(logging.DEBUG)

        self.filelogger.setFormatter(self.formater)
        self.console.setFormatter(self.formater)
        self.logger.addHandler(self.filelogger)
        self.logger.addHandler(self.console)

    def log(self):
        return self.logger


logger = Logger().log()
logger
import os

BASEPATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 报告地址
REPORTPATH = BASEPATH + os.path.sep + 'report' + os.path.sep + 'report.html'

LOGPATH = BASEPATH + os.path.sep + 'log' + os.path.sep

WEBLOGPATH = LOGPATH + 'server.log'

# webcase path
WEBCASEPATH = BASEPATH + os.path.sep + 'test_case'

WEBPICTUREPATH = BASEPATH + os.path.sep + 'report' + os.path.sep + 'picture' + os.path.sep
path
# coding=utf-8
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select


class Pyse(object):
    '''
        Pyse framework for the main class, the original
    selenium provided by the method of the two packaging,
    making it easier to use.
    '''

    def __init__(self, browser='ff'):
        '''
        Run class initialization method, the default is proper
        to drive the Firefox browser. Of course, you can also
        pass parameter for other browser, Chrome browser for the "Chrome",
        the Internet Explorer browser for "internet explorer" or "ie".
        '''
        if browser == "firefox" or browser == "ff":
            driver = webdriver.Firefox()
        elif browser == "chrome":
            option = webdriver.ChromeOptions()
            option.add_argument("--start-maximized")
            driver = webdriver.Chrome(chrome_options=option,)
        elif browser == "internet explorer" or browser == "ie":
            driver = webdriver.Ie()
        elif browser == "opera":
            driver = webdriver.Opera()
        elif browser == "phantomjs":
            driver = webdriver.PhantomJS()
        elif browser == 'edge':
            driver = webdriver.Edge()
        try:
            self.driver = driver
        except Exception:
            raise NameError(
                "Not found %s browser,You can enter 'ie', 'ff', 'opera', 'phantomjs', 'edge' or 'chrome'." % browser)

    def element_wait(self, css, secs=5):
        '''
        Waiting for an element to display.

        Usage:
        driver.element_wait("css=>#el",10)
        '''
        if "=>" not in css:
            raise NameError("Positioning syntax errors, lack of '=>'.")

        by = css.split("=>")[0]
        value = css.split("=>")[1]

        if by == "id":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.ID, value)))
        elif by == "name":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.NAME, value)))
        elif by == "class":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.CLASS_NAME, value)))
        elif by == "link_text":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.LINK_TEXT, value)))
        elif by == "xpath":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.XPATH, value)))
        elif by == "css":
            WebDriverWait(self.driver, secs, 1).until(EC.presence_of_element_located((By.CSS_SELECTOR, value)))
        else:
            raise NameError(
                "Please enter the correct targeting elements,'id','name','class','link_text','xpath','css'.")

    def get_element(self, css):
        '''
        Judge element positioning way, and returns the element.
        '''
        if "=>" not in css:
            raise NameError("Positioning syntax errors, lack of '=>'.")

        by = css.split("=>")[0]
        value = css.split("=>")[1]

        if by == "id":
            element = self.driver.find_element_by_id(value)
        elif by == "name":
            element = self.driver.find_element_by_name(value)
        elif by == "class":
            element = self.driver.find_element_by_class_name(value)
        elif by == "link_text":
            element = self.driver.find_element_by_link_text(value)
        elif by == "xpath":
            element = self.driver.find_element_by_xpath(value)
        elif by == "css":
            element = self.driver.find_element_by_css_selector(value)
        else:
            raise NameError(
                "Please enter the correct targeting elements,'id','name','class','link_text','xpath','css'.")
        return element

    def open(self, url):
        '''
        open url.

        Usage:
        driver.open("https://www.baidu.com")
        '''
        self.driver.get(url)

    def max_window(self):
        '''
        Set browser window maximized.

        Usage:
        driver.max_window()
        '''
        self.driver.maximize_window()

    def set_window(self, wide, high):
        '''
        Set browser window wide and high.

        Usage:
        driver.set_window(wide,high)
        '''
        self.driver.set_window_size(wide, high)

    def type(self, css, text):
        '''
        Operation input box.

        Usage:
        driver.type("css=>#el","selenium")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        el.send_keys(text)

    def clear(self, css):
        '''
        Clear the contents of the input box.

        Usage:
        driver.clear("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        el.clear()

    def click(self, css):
        '''
        It can click any text / image can be clicked
        Connection, check box, radio buttons, and even drop-down box etc..

        Usage:
        driver.click("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        el.click()

    def right_click(self, css):
        '''
        Right click element.

        Usage:
        driver.right_click("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        ActionChains(self.driver).context_click(el).perform()

    def move_to_element(self, css):
        '''
        Mouse over the element.

        Usage:
        driver.move_to_element("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        ActionChains(self.driver).move_to_element(el).perform()

    def double_click(self, css):
        '''
        Double click element.

        Usage:
        driver.double_click("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        ActionChains(self.driver).double_click(el).perform()

    def drag_and_drop(self, el_css, ta_css):
        '''
        Drags an element a certain distance and then drops it.

        Usage:
        driver.drag_and_drop("css=>#el","css=>#ta")
        '''
        self.element_wait(el_css)
        element = self.get_element(el_css)
        self.element_wait(ta_css)
        target = self.get_element(ta_css)
        ActionChains(driver).drag_and_drop(element, target).perform()

    def click_text(self, text):
        '''
        Click the element by the link text

        Usage:
        driver.click_text("新闻")
        '''
        self.driver.find_element_by_partial_link_text(text).click()

    def close(self):
        '''
        Simulates the user clicking the "close" button in the titlebar of a popup
        window or tab.

        Usage:
        driver.close()
        '''
        self.driver.close()

    def quit(self):
        '''
        Quit the driver and close all the windows.

        Usage:
        driver.quit()
        '''
        self.driver.quit()

    def submit(self, css):
        '''
        Submit the specified form.

        Usage:
        driver.submit("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        el.submit()

    def F5(self):
        '''
        Refresh the current page.

        Usage:
        driver.F5()
        '''
        self.driver.refresh()

    def js(self, script):
        '''
        Execute JavaScript scripts.

        Usage:
        driver.js("window.scrollTo(200,1000);")
        '''
        self.driver.execute_script(script)

    def get_attribute(self, css, attribute):
        '''
        Gets the value of an element attribute.

        Usage:
        driver.get_attribute("css=>#el","type")
        '''
        el = self.get_element(css)
        return el.get_attribute(attribute)

    def get_text(self, css):
        '''
        Get element text information.

        Usage:
        driver.get_text("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        return el.text

    def get_display(self, css):
        '''
        Gets the element to display,The return result is true or false.

        Usage:
        driver.get_display("css=>#el")
        '''
        self.element_wait(css)
        el = self.get_element(css)
        return el.is_displayed()

    def get_title(self):
        '''
        Get window title.

        Usage:
        driver.get_title()
        '''
        return self.driver.title

    def get_url(self):
        '''
        Get the URL address of the current page.

        Usage:
        driver.get_url()
        '''
        return self.driver.current_url

    def get_windows_img(self, file_path):
        '''
        Get the current window screenshot.

        Usage:
        driver.get_windows_img()
        '''
        self.driver.get_screenshot_as_file(file_path)

    def wait(self, secs):
        '''
        Implicitly wait.All elements on the page.

        Usage:
        driver.wait(10)
        '''
        self.driver.implicitly_wait(secs)

    def accept_alert(self):
        '''
        Accept warning box.

        Usage:
        driver.accept_alert()
        '''
        self.driver.switch_to.alert.accept()

    def dismiss_alert(self):
        '''
        Dismisses the alert available.

        Usage:
        driver.dismiss_alert()
        '''
        self.driver.switch_to.alert.dismiss()

    def switch_to_frame(self, css):
        '''
        Switch to the specified frame.

        Usage:
        driver.switch_to_frame("css=>#el")
        '''
        self.element_wait(css)
        iframe_el = self.get_element(css)
        self.driver.switch_to.frame(iframe_el)

    def switch_to_frame_out(self):
        '''
        Returns the current form machine form at the next higher level.
        Corresponding relationship with switch_to_frame () method.

        Usage:
        driver.switch_to_frame_out()
        '''
        self.driver.switch_to.default_content()

    def open_new_window(self, css):
        '''
        Open the new window and switch the handle to the newly opened window.

        Usage:
        driver.open_new_window()
        '''
        original_windows = self.driver.current_window_handle
        all_handles = self.driver.window_handles
        for handle in all_handles:
            if handle != original_windows:
                self.driver.switch_to.window(handle)

    # def _save_png(self, name):
    #     self.get_windows_img(name)

    def wait_and_save_exception(self, css, name):
        try:
            self.element_wait(css, secs=5)
            return True
        except Exception as e:
            from lib.path import WEBPICTUREPATH
            self.get_windows_img(WEBPICTUREPATH + name + '.jpg')
            return False

    def wait_and_exception(self, css):
        try:
            self.element_wait(css, secs=10)
            return True
        except Exception as e:
            return False

    def select_by_value(self, css, value):
        self.element_wait(css)
        el = self.get_element(css)
        Select(el).select_by_value(value)



if __name__ == '__main__':
    driver = Pyse("chrome")
pase
import os
from lib.path import WEBPICTUREPATH


class Tool(object):
    def __init__(self):
        self.filelist = os.listdir(WEBPICTUREPATH)

    def error_picture(self):
        picture = []
        for item in self.filelist:
            if item.endswith('.jpg'):
                picture.append((item,))
        return picture

    def clear_picture(self):
        list(map(os.remove, map(lambda file: WEBPICTUREPATH + file, self.filelist)))
tool
'''
主要放页面的元素
'''
from lib.pyse import Pyse
class Base(object):
    def __init__(self):
        self.pyse = Pyse('chrome')
    def open(self):
        self.pyse.open('http://zbox.imdsx.cn/user-login-Lw==.html1')
        #1.第一步打开浏览器,输入网址
    def quit(self):
        self.pyse.quit()
class LoginPage(Base):
    #一个页面一个类,每一个功能点定义为函数
    def send_username(self):
        css = "css=>#account"
        self.pyse.type(css,"admin")
        #定义密码和登录按钮
    def send_passwd(self):
        css = "css=>input[name=""password]"
        self.pyse.type(css,"houyafan123")
    def login(self):
        css = 'css=>#submit'
        self.pyse.click(css)
    def check_login(self):
        css = 'css=>a[href="/user-logout.html"]'
        flag = self.pyse.wait_and_save_exception(css,'test_a_lpgin')
        #校验元素是否存在
        return  flag



if __name__== '__main__':
    page = LoginPage()
    page.open()
    page.send_username()
    page.send_passwd()
    page.login()
#调试当前页面
basepage
'''
用到page,unittest  函数
当前页面写用例,
'''
from pages.basepage import LoginPage
import unittest
class UiTestter(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        '''
        def setUp(self) 当前类下每一条用例运行时候都要先执行一下
        def tearDown(self) 当前类下每一条用例运行结束要执行一次
        def setUpClass(cls)当前类下全部用例以前运行一次
         def tearDownClass(cls)当前类下全部用例以后运行一次
        '''
        cls.page = LoginPage()
        cls.page.open()

    def test_a_lpgin(self):
        self.page.send_username()
        self.page.send_passwd()
        self.page.login()
        self.assertTrue(self.page.check_login())


    @classmethod
    def tearDownClass(cls):
        cls.page.quit()
test_zbox
相关文章
相关标签/搜索