自动化测试:behave

*:first-child {
margin-top: 0 !important; }
body > *:last-child {
margin-bottom: 0 !important; }

a {
color: #4183C4; }
a.absent {
color: #cc0000; }
a.anchor {
display: block;
padding-left: 30px;
margin-left: -30px;
cursor: pointer;
position: absolute;
top: 0;
left: 0;
bottom: 0; }

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
cursor: text;
position: relative; }

h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor {
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA09pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoMTMuMCAyMDEyMDMwNS5tLjQxNSAyMDEyLzAzLzA1OjIxOjAwOjAwKSAgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OUM2NjlDQjI4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OUM2NjlDQjM4ODBGMTFFMTg1ODlEODNERDJBRjUwQTQiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo5QzY2OUNCMDg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo5QzY2OUNCMTg4MEYxMUUxODU4OUQ4M0REMkFGNTBBNCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsQhXeAAAABfSURBVHjaYvz//z8DJYCRUgMYQAbAMBQIAvEqkBQWXI6sHqwHiwG70TTBxGaiWwjCTGgOUgJiF1J8wMRAIUA34B4Q76HUBelAfJYSA0CuMIEaRP8wGIkGMA54bgQIMACAmkXJi0hKJQAAAABJRU5ErkJggg==) no-repeat 10px center;
text-decoration: none; }

h1 tt, h1 code {
font-size: inherit; }

h2 tt, h2 code {
font-size: inherit; }

h3 tt, h3 code {
font-size: inherit; }

h4 tt, h4 code {
font-size: inherit; }

h5 tt, h5 code {
font-size: inherit; }

h6 tt, h6 code {
font-size: inherit; }

h1 {
font-size: 28px;
color: black; }

h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }

h3 {
font-size: 18px; }

h4 {
font-size: 16px; }

h5 {
font-size: 14px; }

h6 {
color: #777777;
font-size: 14px; }

p, blockquote, ul, ol, dl, li, table, pre {
margin: 15px 0; }

hr {
background: transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAECAYAAACtBE5DAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyJpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBNYWNpbnRvc2giIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6OENDRjNBN0E2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6OENDRjNBN0I2NTZBMTFFMEI3QjRBODM4NzJDMjlGNDgiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo4Q0NGM0E3ODY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo4Q0NGM0E3OTY1NkExMUUwQjdCNEE4Mzg3MkMyOUY0OCIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PqqezsUAAAAfSURBVHjaYmRABcYwBiM2QSA4y4hNEKYDQxAEAAIMAHNGAzhkPOlYAAAAAElFTkSuQmCC) repeat-x 0 0;
border: 0 none;
color: #cccccc;
height: 4px;
padding: 0;
}

body > h2:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child {
margin-top: 0;
padding-top: 0; }
body > h1:first-child + h2 {
margin-top: 0;
padding-top: 0; }
body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child {
margin-top: 0;
padding-top: 0; }

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0; }

h1 p, h2 p, h3 p, h4 p, h5 p, h6 p {
margin-top: 0; }

li p.first {
display: inline-block; }
li {
margin: 0; }
ul, ol {
padding-left: 30px; }

ul :first-child, ol :first-child {
margin-top: 0; }

dl {
padding: 0; }
dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px; }
dl dt:first-child {
padding: 0; }
dl dt > :first-child {
margin-top: 0; }
dl dt > :last-child {
margin-bottom: 0; }
dl dd {
margin: 0 0 15px;
padding: 0 15px; }
dl dd > :first-child {
margin-top: 0; }
dl dd > :last-child {
margin-bottom: 0; }

blockquote {
border-left: 4px solid #dddddd;
padding: 0 15px;
color: #777777; }
blockquote > :first-child {
margin-top: 0; }
blockquote > :last-child {
margin-bottom: 0; }

img {
max-width: 100%; }

span.frame {
display: block;
overflow: hidden; }
span.frame > span {
border: 1px solid #dddddd;
display: block;
float: left;
overflow: hidden;
margin: 13px 0 0;
padding: 7px;
width: auto; }
span.frame span img {
display: block;
float: left; }
span.frame span span {
clear: both;
color: #333333;
display: block;
padding: 5px 0 0; }
span.align-center {
display: block;
overflow: hidden;
clear: both; }
span.align-center > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: center; }
span.align-center span img {
margin: 0 auto;
text-align: center; }
span.align-right {
display: block;
overflow: hidden;
clear: both; }
span.align-right > span {
display: block;
overflow: hidden;
margin: 13px 0 0;
text-align: right; }
span.align-right span img {
margin: 0;
text-align: right; }
span.float-left {
display: block;
margin-right: 13px;
overflow: hidden;
float: left; }
span.float-left span {
margin: 13px 0 0; }
span.float-right {
display: block;
margin-left: 13px;
overflow: hidden;
float: right; }
span.float-right > span {
display: block;
overflow: hidden;
margin: 13px auto 0;
text-align: right; }

code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }

pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }

.highlight pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }

pre {
background-color: #f8f8f8;
border: 1px solid #cccccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px; }
pre code, pre tt {
background-color: transparent;
border: none; }

sup {
font-size: 0.83em;
vertical-align: super;
line-height: 0;
}

kbd {
display: inline-block;
padding: 3px 5px;
font-size: 11px;
line-height: 10px;
color: #555;
vertical-align: middle;
background-color: #fcfcfc;
border: solid 1px #ccc;
border-bottom-color: #bbb;
border-radius: 3px;
box-shadow: inset 0 -1px 0 #bbb
}

* {
-webkit-print-color-adjust: exact;
}
@media screen and (min-width: 914px) {
body {

margin:0 auto;
}
}
@media print {
table, pre {
page-break-inside: avoid;
}
pre {
word-wrap: break-word;
}
}
-->
code[class*="language-"],
pre[class*="language-"] {
background: #f5f2f0;
}

/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}

.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: slategray;
}

.token.punctuation {
color: #999;
}

.namespace {
opacity: .7;
}

.token.property,
.token.tag,
.token.boolean,
.token.number,
.token.constant,
.token.symbol,
.token.deleted {
color: #905;
}

.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #690;
}

.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string {
color: #a67f59;
background: hsla(0, 0%, 100%, .5);
}

.token.atrule,
.token.attr-value,
.token.keyword {
color: #07a;
}

.token.function {
color: #DD4A68;
}

.token.regex,
.token.important,
.token.variable {
color: #e90;
}

.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}

.token.entity {
cursor: help;
}
-->

在系统开发过程中,我们一般个人参与的开发都是局部的,自己负责的一部分与其它团队成员的成果组合在一起才能实现用户的完整行为。比如常见的电商系统就有几个主要的流程

  • 商品搜索
  • 购物车
  • 订单
  • 支付
  • 物流

这些模块复杂的足以形成各自的团队,不同团队相互之间依据一定的接口来配合协作。在开发阶段可以基于接口各自独立开发,对于依赖其它模块的接口可以通过接口mock来完成。但mock方式本身是有使用场景的,一旦依赖方接口稳定后,就会调用实际服务来代替mock接口。

场景A: 在上面提到的购物流程都完善的前提下,一个做物流系统的同事需要真实模似真实的用户场景产生物流单,他需要去相应的环境进行商品搜索,加入购物车,登录,下单,付款等众多操作之后才会轮到他的模块登场。想想都是件相当繁琐的事情,所以希望有一种很快捷的方式代替人工去完成这些复杂且花时间的体力劳动。当然你也可以找测试妹子说:那个谁,帮我在某某环境下一个单我测试物流单逻辑。

期望只需要执行一条命令,就能快速得到指定条件的订单。

场景B: 在上面提到的购物流程中,任意修改某个流程都有可能对整体流程构成不同程度的影响,有没有快速简捷的方式给我们确认新的修改是否会影响主流程的变更呢?一般的作法就是需要测试人员去回归主流程,但这个成本比较高而且并一定那么的可靠,我们需要一种成本低又不知疲倦的工具为我们完成上面的工作,即使达不到100%人工测试的效果。

期望在代码提交后,每日构建工具能够在修改之后的版本上执行主流程的测试用例,确保第一时间反馈出问题来,而不需要等到测试人员报BUG或者是线上用户反馈出问题来才被动知道。

场景C:

在做一个稍微大型的功能后,为了确保各个子功能能够相互协作正常,我们一般首先会对子功能做单元测试,然后对大功能做集成测试。在集成测试时,需要快速的定义测试用例并得到预期结果。

集成测试的方式可能有很多种,比如我之前对http api接口的集成测试就依靠谷歌的postman(当然你也可以用junit来搞集成测试,在里面做各种断言)。但这种方式需要人工判断接口是否正确,因为此工具只具备执行能力并不具备判断能力。所以需要一款脱离特定语言的测试用例工具来帮助我们完成,而且非常容易的能够对环境进行扩展,比如定义开发环境,测试环境,预上线环境,生产环境等。

behave简要说明

依赖项

与python配合完成,所以需要在执行测试用例的机器上至少需要安装:

  • python
  • behave

另外可以为behave创建单独的python环境,可以引入virtualenv。每次运行时通过source xxxenv/bin/activate来进入特定的python环境,source的目的就是替换环境变量。

其它组件

比如我主要测试http api,所以会用到下面一些库:

  • requests, 用于做http请求的
  • json,用于处理字符串与json之间的各种转换
  • operator,操作符,比如a>b之类的函数表达

参考文档

https://pythonhosted.org/behave/index.html

项目背景

针对HTTP API的集成测试的自动化。上面所说的场景A/B/C是我暂时理解的,不同的人在不现的阶段对自动化测试的需求不一样。比如我做为业务系统的开发者,场景C可以帮助在我提交大型功能前做联调测试,系统稳定后,我们去修改一个功能但依赖其它模块数据时,希望快速产生预期数据那么场景A适合我们。当我们比较惶恐的修改某种功能时,场景B的主流程测试能够给我们信心。

项目结构

这里以文章前面说的购物场景为例。

envbehave

是创建的一个python独立环境,可选。

features

behave相关的所有测试用例文件

  • dev 存放测试用例的目录,可以按业务定义名称好作区分,比如订单相关的可以叫 order。
  • steps,存放配置测试用例文件的执行文件,behave+python
  • environment.py,是为了支持多环境而创建的,比如开发,测试,预上线,生产环境可任意切换
  • service.py,封装了基础功能,目的就是简化step以及测试用例的代码

代码实现

多环境支持

behave提供了对于环境的控制,我们可以在如下函数中添加自己的逻辑:

  • before_step
  • before_scenario
  • before_feature
  • before_tag
  • before_all

根据之前所述,集成测试可能涉及到不同小组提供的api,所以可以定义如下数据:

CONFIG = {
    ‘dev‘: {
        ‘hosts‘: {
            ‘product‘: ‘http://localhost:1234/api/product‘,
            ‘order‘:‘http://localhost:1234/api/order‘,
            ‘cart‘: ‘http://localhost:1234/api/cart‘,
            ‘pay‘: ‘http://localhost:1234/api/pay‘,
            ‘user‘: ‘http://localhost:1234/api/user‘,
            ‘logistics‘: ‘http://localhost:1234/api/logistics‘,
        }
    },
    ‘test‘: {
        ‘hosts‘: {
            ‘product‘: ‘http://test.jim.com/api/product‘,
            ‘order‘:‘http://test.jim.com/api/order‘,
            ‘cart‘: ‘http://test.jim.com/api/cart‘,
            ‘pay‘: ‘http://test.jim.com/api/pay‘,
            ‘user‘: ‘http://test.jim.com/api/user‘,
            ‘logistics‘: ‘http://test.jim.com/api/logistics‘,
        }
    },

}

然后在before_all中进行数据初始化,环境参数可以通过命令行的-D参数来控制,比如: -D env=dev

env = ‘dev‘
def before_all(context):
    global env
    if (context.config.userdata.get(‘env‘)):
        env = context.config.userdata[‘env‘]

    for k, v in CONFIG[env][‘hosts‘].items():
        hosts[k] = v

基础功能封装

封装通用的功能,便于使用测试用例简单方便,容易管理。创建一个service.py,主体结构如下:

#coding=utf-8
import requests, json

hosts = {}
class BddService(object):
    def __init__(self, api, data={}, headers={}):
       # 数据初始化

    def __before__(self, context, data, url):

       # 处理数据,比如从测试用例中取参数,存放到context的requestData中,供后续的http请求使用

    def __after__(self, context, r, url):
       # 从http request中获取数据,存放到context的responseData中,供后续的断言使用

    def get(self, context, url, data={}):
       # 完成 http 调用
  • 测试用例参数指定

我们需要在用例下面直观灵活的指定参数,可以通过behave提供的文本功能实现,它可以读一段多行文本到context.text变量中,然后我们对去做处理。

When 搜索商品
    """
    {"name":"product1"}
    """

before函数中完成值的填充,将最终的请求参数存放在context的requestData变量中。


def __before__(self, context, data, url):

    if context.text:
        print (context.text)
        o = json.loads(context.text)
        print (o)
        for k in o:
            data[k] = o[k]
    context.requestData = data
  • HTTP请求结构处理

after函数中完成取值,将HTTP请求的结构存放在context的responseData变量中。对于HTTP请求的结构支持两类数据,一类是json数据,一类是简单值(比如直接返回一个数字或者一个bool值或者是一个字符串)。

def __after__(self, context, r, url):
    try:
        context.response = r.json()
        if context.response.get(‘value‘, None):
            context.responseData = context.response.pop(‘value‘)
            try:
                if type(context.responseData) == str or type(context.responseData) == unicode:
                    context.responseData = json.loads(context.responseData)
           except:
        if not hasattr(context, ‘responseData‘) or context.responseData == None:
   except:
        context.response = r.text

上面逻辑中的get(‘value‘),是特殊的数据结构(约定HTTP接口都会按一定的固定格式返回),比如我这里的结构,其中的value才是真正的业务数据。

{
    "result": true,
    "error": null,
    "value": [
        {
            "id": 1,
            "name": "product1",
            "productImage": null
        }
    ]
}

断言

behave默认情况下进行断言,需要在@then中完成断言,就需要为每个测试用例编写独立的断言函数,可以做统一的封装,主体支持两类操作。

  • 判断请求响应是否正常
  • 判断请求的值是否符合预期

创建一个assert.py

  • 编写两个断言函数

从@then脚本后面读取多行文本,如果为空直接跳过断言。

@then(u‘得到响应数据‘)
def step_impl(context):
    if not context.text:
        return
    try:
        expect = json.loads(context.text)
    except:
        expect = context.text
    assertObj(expect, context.responseData)

@then(u‘得到响应‘)
def step_impl(context):
    if not context.text:
        return
    expect = json.loads(context.text)
    assertObj(expect, context.response)
  • 编写断言函数

需要判断比较值的类型,因为只支持对基本类型的数据做断言,如果是列表就需要迭代到成员对象,至于迭代到基本数据类型(比如字符串,数字),然后利用operator库做处理。

def assertObj(expect, actual):
    if(type(expect) == list):
        for i in range(len(expect)):
            assertObj(expect[i], actual[i])
    elif type(expect)==bool or type(expect)==str or type(expect)==int:
        assertObjKey(None, expect, actual)
    else:
        for k in expect:
            if(type(expect[k]) == dict or type(expect[k]) == list):
                if(type(actual[k]) != type(expect[k])):
                    actual[k] = json.loads(actual[k])
                assertObj(expect[k], actual[k])
            else:
                assertObjKey(k, expect[k], actual[k])

def assertObjKey(k,originExpect,actualValue):
    #测试用例的值支持<,<=,<,<=,!=,==
    #样例数据:{"premium":"ge$0"}
    expectArray = str(originExpect).split("$");

    if (len(expectArray) == 2):
        action = expectArray[0];
        realExpect = expectArray[1]
       if action == "ge":
            assert operator.ge(actualValue, long(realExpect))
        elif action == "gt":
            assert operator.gt(actualValue, long(realExpect))
        elif action == "le":
            assert operator.le(actualValue, long(realExpect))
        elif action == "lt":
            assert operator.lt(actualValue, long(realExpect))
        elif action == "ne":
            assert operator.ne(actualValue, realExpect)
        elif action == "eq":
            assert operator.eq(actualValue, realExpect)
        else:
            assert originExpect == actualValue
    else:
        assert originExpect == actualValue

编写step

可以根据调用的不同业务接口创建不同的step文件,比如如下图所示:

这里贴一个登录的step脚本示例,其余的大同小异。

R = BddService(‘user‘)

@given(u‘初始化数据‘)
def given_init(context):
    context.userName="jim"
    context.password="123456"

@when(u‘登录‘)
def step_impl(context):
    R.get(context,"/login",{"userName":context.userName,"password":context.password})

创建实例

python中创建实例时没有关键字new,这与其它语言有比较大的区别,刚开始总是觉得别扭,现在看还是别扭。

完成测试用例

创建一个order.feature


Feature:订单流程测试

Scenario:常规下单流程

    Given 初始化数据

    When 登录
    Then 得到响应
    """
    {"result":true}
    """

    When 搜索商品
    """
    {"name":"product1"}
    """
    Then 得到响应
    """
    {"result":true}
    """

    When 加入购物车
    Then 得到响应
    """
    {"result":true}
    """

    When 提交订单
    Then 得到响应数据
    """
    1
    """

    When 支付订单
    Then 得到响应数据
    """
    1
    """

    When 生成物流单
    Then 得到响应数据
    """
    1
    """

执行测试用例

只需要在对应的目录执行如下脚本即可愉快的执行测试用例。

behave -D env=test features/dev/order.feature

如果运行正常,会看出如下的输出,黄色的代表执行通过,如果执行失败会打印出错误信息,以及用例执行到哪一步报错。另外说明下,behave在执行正常的情况下会屏蔽通过print输出的日志,貌似可以通过参数调,有兴趣的可以研究研究。

// )[\w\W]*?(?=)/i,lookbehind:!0,inside:Prism.languages.javascript,alias:"language-javascript"}}),Prism.languages.js=Prism.languages.javascript;
// ]]>

时间: 2024-10-01 22:38:34

自动化测试:behave的相关文章

直播|python大咖实力领跑,分分钟扫盲电商网站自动化测试框架开发

作为大数据时代的软件测试工程师--你应该会的更多,还在单纯的只会点页 面测试BUG?又或者只懂功能测试技能.接口功能测试技能.自动化测试.性 能测试.敏捷测试.大数据其中某一个?是时候掌握新技能了,康忙北鼻! [前言] Selenium一直以来都被视作测试人员成功向自动化脚本开发转型的首选入门, 随着python语言的火热程度的持续攀升,基于python+Selenium实现自动化脚本 的开发也备受业内测试人员的追捧. 本课程基于Selenium3,python及BDD框架,结合大型电商京东实战

初识gauge自动化测试框架(二)

看到一些同学对该工具有点一兴趣,那么我将继续介绍Gauge自动化测试工具. Gauge本质上一个BDD(Behavior Driven Development)测试框架.所以,首先你要了解BDD的操作方式. BDD包含两部分,一部分是: 软件行为描述.另一部分是: 针对描述编写测试代码 . 首先,行为描述文件描述如下. # 计算器 我想实现一个简单的计算器,这个计算器可以做两个数的加.减.乘.除运算. ## 测试加法 * 创建Calculator类. * 相使用add方法,计算3 加5 的结果为

自动化测试到底是什么

引子 偶然在群里有人问自动化测试到底是啥,搞不懂.qtp对象库好麻烦,jmeter怎么做测试....一堆一堆的问题.其实说实话真心不知道该咋解答了,我的内心是累的~ 突然想到自己的新书里不就解释过这些吗!看来还是很多童鞋对于自动化测试的认知存在巨大的问题啊! so,以下内容选择<小强软件测试疯狂讲义> 重新认识性能测试之后我们再来看看自动化测试到底是什么.其实这个话题我在不同的场合多次谈过,甚至在我创办的"挨踢脱口秀"中也专门做了一次节目来说明,但可惜的是仍然有很多朋友对自

自动化测试框架 selenium api的封装

接上一篇 http://tianxietaotao.blog.51cto.com/12002420/1951701 这篇我大概介绍下我这个工具的简单介绍 先上图: 制作背景: Web自动化测试在现在测试领域已经越来越普遍,但是写代码对于好多测试猿代码基础较弱,搭建系统也比较麻烦.所以我抽闲暇时间做了这个简单的工具:下面简单介绍下功能 工具简单介绍: 1.工具栏:Resume:调试阶段执行到下一个断点 next:单步执行 debug/run 模式切换 执行.停止 2.用例树:用例采用execl或者

Selenium+Java+Eclipse 自动化测试环境搭建

一.下载Java windows java下载链接 https://www.java.com/zh_CN/download/win10.jsp 二.安装Java 安装好后检查一下需不需要配置环境变量,现在java 8已经不用配置环境变量了,直接在命令行输入:java -version 三.下载和安装Eclipse windows Eclipse下载链接 https://www.eclipse.org/downloads/ 你也可以下载绿色版 四.下载selenium,然后解压 selenium

Android自动化测试工具实现简述

前言 自动化测试在产品开发和测试中都有着非常重要的作用.在产品开发阶段,可靠又重复性地运行以确保没有引进回归问题:在产品测试阶段,可以节省人力成本和时间成本,并能保证更大范围的覆盖.Android自动化测试工具同样可以节省不少人力和时间成本,对其研究和实现对于提高测试效率具有一定的意义.目前市面上也有不少Android自动化测试工具,本人在现有工具的基础上,加上自己的理解和实践向大家介绍自动化测试工具的原理和实现. 了解自动化测试的一定对Robotium并不陌生,Robotium是一款国外的An

Python+Selenium进行UI自动化测试项目中,常用的小技巧2:读取配置文件(configparser,.ini文件)

在自动化测试项目中,可能会碰到一些经常使用的但 很少变化的配置信息,下面就来介绍使用configparser来读取配置信息config.ini 读取的信息(config.ini)如下: [config]platformName=AndroidappPackage=com.sheinsideappActivity=.module.GuideActivitybaseUrl=http://0.0.0.0:4723/wd/hubfindElementTimes=10[cmd]openAppium=nod

自动化测试--登录页面验证码问题

对于web应 用来说,大部分的系统在用户登录时都要求用户输入验证码,验证码的类型的很多,有字母数字的,有汉字的,甚至还要用户输入一条算术题的答案的,对于系统来 说使用验证码可以有效果的防止采用机器猜测方法对口令的刺探,在一定程度上增加了安全性.但对于测试人员来说,不管是进行性能测试还是自动化测试都是一个 棘手的问题. 下面来谈一下处理验证码的几种方法. 去掉验证码 这是最简单的方法,对于开发人员来说,只是把验证码的相关代码注释掉即可,如果是在测试环境,这样做可省去了测试人员不少麻烦,如果自动化脚

Robot Framework自动化测试(五)--- 开发系统关键字

最近一直在用robot framework 做自动化测试项目,老实说对于习惯直接使用python的情况下,被框在这个工具里各种不爽,当然,使用工具的好处也很多,降低了使用成本与难度:当然,在享受工具带来便利的同时也会受制于工具.对于特定的需求,工具没提供相关的Library和关键字的时候,就只能放弃了. 还好robot framework提供了 Evaluate 关键字,对于Evaluate 关键字的使用等有时间再讲.当robot framework 不能解决需求,我是直接写个.py 程序,通过