正文
手把手教你接口自动化测试 – SoapUI & Groovy
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
手把手教你接口自动化测试 – SoapUI & Groovy
http://www.cnblogs.com/wade-xu/p/4236295.html
关键词:SoapUI接口测试,接口自动化测试,数据驱动测试,SoapUI进阶使用, Groovy in SoapUI, SoapUI中Groovy的使用,数据分离。
阅读这篇文章需要一定的SoapUI基础,至少入过门,另外还需要一些Groovy的知识,当然如果你会java 也可以,这里用到的Groovy知识和Java很类似。
另外,本文的思路和我上一篇文章<零成本实现接口自动化测试 – Java+TestNG 测试Restful service>很相似,只不过把Java+TestNG的组合换成了SoapUI+Groovy, 另外测试对象也换成了基于Soap的web service, 依旧用Excel来管理数据,做到数据分离。
由于我用到的SoapUI是免费版本,相比Pro版,少很多的功能,像DataLoop之类的,所以只能通过Groovy写一些脚本来做数据驱动的测试。
首先打开SoapUI, 新建一个Workspace 名为Demo
然后点击File->New soapUI Project
然后输入你的Project Name, WSDL 地址 点击OK
输入服务的用户名密码 点击OK
项目工程建好了
右击ServicePort 建立TestSuite
以其中一个接口为例 来生成用例
输入TestSuite name 然后确认
工程结构如下
通过右击TestCase -> Add Step 增加 Groovy Script 和 Properties
增加四个Groovy Script, 并且命名成 Start, Process, Check Response, End
增加5个 Properties, 并且命名成Input, Baseline, Output, Result, fieldResult
调整它们的顺序,最后形成下图的工程目录结构
Start脚本主要创建log文件
/*Check the log file, create folder and file if necessary*/
import java.io.*;def cal = Calendar.instance;
def sysdate = cal.getTime();
def Y = cal.get(Calendar.YEAR);
def M = cal.get(Calendar.MONTH)+1;
def D = cal.get(Calendar.DATE);
if (D<10) D = "0"+D;
if (M<10) M = "0"+M;
date = Y+"-"+M+"-"+D;
time=sysdate.toString().replaceAll(':','-')def testSuites=testRunner.testCase.getTestSuite();
def testcase = testRunner.testCase;def logFolder = new File(context.expand('${#Project#LogFolder}'));
def responseLogName = (context.expand('${#Project#LogFolder}')+date+'\\'+testSuites.name+' - '+ testcase.name +' - ' + time+".log");
def responseDetailLogName = (context.expand('${#Project#LogFolder}')+date+'\\'+testSuites.name+' - ' + testcase.name +' - ' + time + " Response Detail.log");
def responseLogFile = new File(responseLogName);
def responseDetailLogFile = new File(responseDetailLogName);
def subFolder= new File (context.expand('${#Project#LogFolder}')+date+'\\')/*Set date and Log Name to Project - Testcase Properties*/
testcase.setPropertyValue('date', date);
testcase.setPropertyValue('LogFile - Check Response', responseLogName);
testcase.setPropertyValue('LogFile - Response Detail', responseDetailLogName);if(!logFolder.exists()){
logFolder.mkdirs();
}if(!subFolder.exists()){
subFolder.mkdirs();
}/*Check the file, create a new one if not found*/
if(!responseLogFile.exists()){
responseLogFile.createNewFile();
}
responseLogFile.append("---------------Test Start on "+sysdate+" ------------------------"+'\n');if(!responseDetailLogFile.exists()){
responseDetailLogFile.createNewFile();
}
responseDetailLogFile.append("---------------Test Start on "+sysdate+" ------------------------"+'\n');
View Script - Start
Process脚本是整个工程的核心,读取Excel数据文件的Input, Baseline 放入二维数组,然后循环读入Input和Baseline这两个Properties, 调用request, 取到Ouput和Result Properties的值放入Output, Result数组,最后更新Excel的Output, Result, Comparison sheet。
import java.io.*;
import jxl.*;
import java.text.DecimalFormat;def readInput(workbook,inputSheetName)
{
Sheet sheet=workbook.getSheet(inputSheetName); rows = sheet.getRows();
columns = sheet.getColumns();/*Get content into array*/
input = new Object [columns][rows]
for (a=0;a<columns;a++)
{
for (b=0;b<rows;b++)
{
input[a][b]= sheet.getCell(a,b).getContents();
}
}
}def readBaseline(workbook,sheetName)
{
Sheet sheet=workbook.getSheet(sheetName); Rows = sheet.getRows();
Columns = sheet.getColumns();/*Get content into array*/
baseline = new Object [Columns][Rows]
for (a=0;a<Columns;a++)
{
for (b=0;b<Rows;b++)
{
baseline[a][b]= sheet.getCell(a,b).getContents();
}
}
}def updateOutput(writableWorkbook,sheetName,start_row,rows,columnNo,result,resultTag){ Sheet[] sheet= writableWorkbook.getSheets();
ws = writableWorkbook.getSheet(sheetName);
if(ws==null){
ws = writableWorkbook.createSheet(sheetName,sheet.length)
}
for (a=0;a<columnNo;a++)
{
ws.addCell(new jxl.write.Label(a,0,result[a][]));
for (b=start_row;b<rows;b++)
{
wc = new jxl.write.WritableCellFormat();
if (resultTag[a][b]=='PASS')
{
wc.setBackground(jxl.format.Colour.WHITE);
ws.addCell(new jxl.write.Label(a,b,result[a][b],wc));
}
else if(resultTag[a][b]=='FAIL'){
wc.setBackground(jxl.format.Colour.RED);
ws.addCell(new jxl.write.Label(a,b,result[a][b],wc));
}
}
}
}def updateResult(writableWorkbook,sheetName,start_row,rows,columnNo,result){ Sheet[] sheet= writableWorkbook.getSheets();
ws = writableWorkbook.getSheet(sheetName);
if(ws==null){
ws = writableWorkbook.createSheet(sheetName,sheet.length)
}
for (a=0;a<columnNo;a++)
{
ws.addCell(new jxl.write.Label(a,0,result[a][]));
for (b=start_row;b<rows;b++)
{
wcf = new jxl.write.WritableCellFormat();
wcf.setBackground(jxl.format.Colour.RED); if(result[a][b] == 'FAIL'){
ws.addCell(new jxl.write.Label(a,b,result[a][b],wcf));
} else
ws.addCell(new jxl.write.Label(a,b,result[a][b]));
}
} wc = new jxl.write.WritableCellFormat();
wcc = new jxl.write.WritableCellFormat();
wc.setBackground(jxl.format.Colour.GRAY_25);
wcc.setBackground(jxl.format.Colour.LIGHT_TURQUOISE);
ws.addCell(new jxl.write.Label(0,rows-3,result[][rows-3],wcc));
ws.addCell(new jxl.write.Label(0,rows-2,result[][rows-2],wc));
ws.addCell(new jxl.write.Label(0,rows-1,result[][rows-1],wc));}def updateComparison(writableWorkbook,sheetName,start_row,rows,columnNo,output,outputTag,result,baseline){ Sheet[] sheet= writableWorkbook.getSheets();
ws = writableWorkbook.getSheet(sheetName);
if(ws==null){
ws = writableWorkbook.createSheet(sheetName,sheet.length)
}
for (a=0;a<columnNo;a++)
{
ws.addCell(new jxl.write.Label(a,0,output[a][])); x= 1;
for (b=start_row;b<rows;b++)
{
if(result[][b] == 'FAIL'){
wc = new jxl.write.WritableCellFormat();
if (outputTag[a][b]=='PASS')
{
wc.setBackground(jxl.format.Colour.WHITE);
ws.addCell(new jxl.write.Label(a,x,output[a][b],wc));
}
else {
wc.setBackground(jxl.format.Colour.RED);
ws.addCell(new jxl.write.Label(a,x,output[a][b],wc));
}
wbc = new jxl.write.WritableCellFormat();
wbc.setBackground(jxl.format.Colour.ICE_BLUE);
ws.addCell(new jxl.write.Label(a,x+1,baseline[a][b],wbc));
x+=2;
}
}
}
}def removeSheetByName(writableWorkbook, name){ Sheet[] sheet= writableWorkbook.getSheets();
ws = writableWorkbook.getSheet(name);
if(ws != null){
for (i = 0; i < sheet.length; i++) {
sheetName = writableWorkbook.getSheet(i).getName();
if (sheetName.equalsIgnoreCase(name)) {
writableWorkbook.removeSheet(i);
}
}
}
}def setProperties(Name,Value,Place)
{
name = Name;
target = testRunner.testCase.getTestStepByName(Place);
target.setPropertyValue(name,Value);
}def cleanProperty(PropertyListName)
{
PropertyList = testRunner.testCase.getTestStepByName(PropertyListName);
size=PropertyList.getPropertyCount();
if (size!=0)
{
for (i=0;i<size;i++)
{
PropertyList.removeProperty(PropertyList.getPropertyAt(0).name);
}
}
}def logFile = new File(context.expand('${#TestCase#LogFile - Check Response}'));
def xlsName = context.expand('${#TestCase#Workbook}');def project = testRunner.testCase.getTestSuite().getProject();
def testSuite = testRunner.testCase.getTestSuite();
def testcase = testRunner.testCase
def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class )
def request = requests[];inputSheetName = "Input";
baselineSheet = "Baseline";
outputSheet = "Output";
resultSheet = "Result";
fieldResult = testcase.getTestStepByName('fieldResult');
ComparisonSheet = "Comparison";Baseline = testcase.getTestStepByName(baselineSheet);
baselineSize = Baseline.getPropertyCount();
Output = testcase.getTestStepByName(outputSheet);def cal = Calendar.instance;
def sysdate = cal.getTime();
sleepTime=context.expand('${#Project#sleepTime}').toInteger()try{
Workbook workbook=Workbook.getWorkbook(new File(xlsName));
cleanProperty(inputSheetName);
readInput(workbook,inputSheetName); for (i=0;i<columns;i++)
{
setProperties(input[i][],'',inputSheetName)
} cleanProperty(baselineSheet);
readBaseline(workbook,baselineSheet);
for (i=0;i<Columns;i++)
{
setProperties(baseline[i][],'',baselineSheet)
}
workbook.close();}catch(Exception e){
e.printStackTrace();
}/*-----------Set runSelect as 'true' in Project property to run selected test cases from startTag till endTag-------*/
def runSelected = context.expand('${#Project#runSelected}')
start_Test=1;
end_Test=rows-1;def passNumbers = 0;
def decFormat = new DecimalFormat("##.00%"); if ('true'.equalsIgnoreCase(runSelected))
{
startTag=context.expand('${#Project#startTag}').toInteger();
endTag=context.expand('${#Project#endTag}').toInteger(); if((0<startTag)&&(startTag<rows)&&(endTag>=startTag)&&(rows>endTag)){
start_Test=startTag;
end_Test=endTag;
}
} result = new Object [][rows+3]
result[][]='Case Description';
result[][]='Result'
result[][rows+1]='Start Time:';
result[][rows+1]=sysdate.toString();/*--New object and put the output name and value into this list--*/
output = new Object [baselineSize][rows]
outputTag = new Object [baselineSize][rows]
for (i=0;i<baselineSize;i++)
{
output[i][]= Baseline.getPropertyAt(i).name;
outputTag[i][]= 'PASS';
} for (m=start_Test;m<=end_Test;m++)
{
logFile.append('\n'+ testcase.name + ": "+m+" "+ ". "+sysdate+'\n');
for (i=0;i<columns;i++)
{
setProperties(input[i][],input[i][m],inputSheetName)
}
for (j=0;j<Columns;j++)
{
setProperties(baseline[j][],baseline[j][m],baselineSheet)
} testRunner.runTestStepByName(request.name);
Thread.sleep(sleepTime);
testRunner.runTestStepByName("Check Response"); result[][m]=context.expand('${'+inputSheetName+'#Case Description}')
result[][m]=context.expand('${'+resultSheet+'#result}') if(result[][m] == 'PASS'){
passNumbers++;
} for (i=0;i<baselineSize;i++)
{
output[i][m]= Output.getPropertyAt(i).value;
outputTag[i][m]= fieldResult.getPropertyAt(i).value;
}
}
result[][rows+2]='End Time:';
result[][rows+2]=sysdate.toString();
result[][rows]='Pass Percentage:'; passPercentage = decFormat.format(passNumbers/(end_Test-start_Test+1));
result[][rows] = passPercentage/*--------------Update Output, Result, Comparison sheet---------*/
try{
workbook = Workbook.getWorkbook(new File(xlsName));
writableWorkbook = Workbook.createWorkbook(new File(xlsName), workbook); updateOutput(writableWorkbook,outputSheet,start_Test,end_Test+1,baselineSize,output,outputTag);
updateResult(writableWorkbook,resultSheet,start_Test,rows+3,2,result); removeSheetByName(writableWorkbook,ComparisonSheet); if(passPercentage != '100.00%'){
updateComparison(writableWorkbook,ComparisonSheet,start_Test,end_Test+1,baselineSize,output,outputTag,result,baseline);
} writableWorkbook.write();
writableWorkbook.close();
workbook.close(); }catch(Exception e){
e.printStackTrace();
} setProperties('passPercentage', passPercentage ,'Result'); testRunner.gotoStepByName('End');
View Script - Process
Check Response 顾名思义,用来检查返回结果, 通过XmlHolder getNodeValue 来取response各节点的值,并且填入Output Properties已作对比之用。
import java.lang.*;
import java.util.*;
import groovy.lang.*;
import groovy.util.*;
import com.eviware.soapui.support.XmlHolderbaselineSheet = "Baseline";
outputSheet = "Output";
resultSheet = "Result";def testcase = testRunner.testCase;
Baseline = testcase.getTestStepByName(baselineSheet)
baselineSize = Baseline.getPropertyCount();
Output = testcase.getTestStepByName(outputSheet);def requests = testcase.getTestStepsOfType( com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep.class )
def request = requests[];
def response = request.testRequest.response;respXmlHolder = new XmlHolder(response.contentAsXml)//declare namespace in xml response
respXmlHolder.declareNamespace("ns1", "http://schemas.xxx.com/v201203/yourservice")def statusCode = request.testRequest.response.responseHeaders["#status#"].toString();def setProperties(Name,Value,Place){
name = Name;
target = testRunner.testCase.getTestStepByName(Place);
target.setPropertyValue(name,Value);
}def getspecifiedValue(field){
prefix = "//ns1:";
nodePath = "${prefix}${field}"
specifiedValue = respXmlHolder.getNodeValue("${nodePath}")
}testRunner.testCase.getTestStepByName(outputSheet).clearPropertyValues();//normal output, status = '200 OK'
if(statusCode.contains('200 OK')){
for (i=1;i<baselineSize;i++)
{
specifiedName = Baseline.getPropertyAt(i).name;
specifiedValue = getspecifiedValue(specifiedName);
if(specifiedValue != null){
setProperties(specifiedName,specifiedValue,outputSheet)
} else {
setProperties(specifiedName,'',outputSheet)
}
}} else
{
setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
setProperties(Baseline.getPropertyAt(1).name,statusCode,outputSheet); for(t=2; t<baselineSize; t++){
setProperties(Baseline.getPropertyAt(t).name, '' ,outputSheet);
}
}setProperties(Baseline.getPropertyAt(0).name,Baseline.getPropertyAt(0).value,outputSheet);
setProperties('result','PASS', resultSheet);logFile = new File(context.expand('${#TestCase#LogFile - Check Response}'));
responseDetailLogFile= new File(context.expand('${#TestCase#LogFile - Response Detail}'));logFile.append(" ------ Start Response Check "+ " @ "+Calendar.instance.getTime()+"\n");
responseDetailLogFile.append("\n"+ testcase.name + " -- " + Baseline.getPropertyAt(0).value+ "\n" + response+"\n");/*--------Compare the result with Baseline and update the result accordingly---------*/for (i=0;i<baselineSize;i++)
{
if (Baseline.getPropertyAt(i).value==Output.getPropertyAt(i).value)
{
setProperties(Baseline.getPropertyAt(i).name,'PASS','fieldResult');
}
else
{
setProperties(Baseline.getPropertyAt(i).name,'FAIL','fieldResult');
setProperties('result','FAIL','Result');
}
}
View Script - Check Response
End脚本 在log上打时间戳
def cal = Calendar.instance;
def sysdate = cal.getTime();responseLogFile = new File(context.expand('${#TestCase#LogFile - Check Response}'));
responseDetailLogFile= new File(context.expand('${#TestCase#LogFile - Response Detail}'));responseLogFile.append('\n'+ "---------------Test End on " + sysdate.toString() + " ------------------------"+'\n');
responseDetailLogFile.append('\n'+ "---------------Test End on " + sysdate.toString() + " ------------------------"+'\n');
View Script - End
配置
双击DemoProject, 点击下方的Properties tab
然后 Add property
Add 如下图所示的5个Property
双击项目工程列表里的'Demo TestCase'
点击Properties tab
Add Property 如图
Value 填Excel 的路径
Excel数据工作簿里的Input sheet 如图
接下来需要把Input里的column name 与 Soap request里的input 字段映射起来
双击Test Steps 里的request
将xml文件里的?用参数来代替
左下角的TestRequest Properties 要填上用户名 密码
Baseline sheet里要把输出结果的字段名都定义好, 因为是根据字段名去response里取结果的
每条用例期望结果都写好,用作和实际结果对比
另外Check Response里的脚本需要设置一下
假设你的response xml文件结构如下
如果你需要检查Soap body标签下的内容, 则你需要配置一下Check Response的脚本
将xml namespace的路径配置一下
右击Project Save一下Project
最后可以运行了 双击Demo TestSuite 点击Run
注意:Groovy脚本也是用第三方的jxl.jar操作excel文件的,所以这个jar需要放到SoapUI安装目录的\lib下面,才能运行成功。
打开Workbook 数据工作簿查看结果
Output
Result
Comparison
是不是跟我上一篇文章异曲同工?
注:转载需注明出处及作者名,严禁恶意转载,尊重原作者的劳动成果。
手把手教你接口自动化测试 – SoapUI & Groovy的更多相关文章- 手把手教你接口自动化测试 – SoapUI &; Groovy【转】
手把手教你接口自动化测试 – SoapUI & Groovy Posted on 2015-01-21 09:38 WadeXu 阅读(12741) 评论(10) 编辑 收藏 手把手教你接口自 ...
- 手把手教你ranorex_android自动化测试第一个示例
要说android的自动化,那真是折腾死我了,从早期的monkeyrunner,到后来的robotium,再到最新的uiautomator,各有各的问题,总之性价比都不够高,不太适合我的使用场景.于是 ...
- SoapUI+excel接口自动化测试简述
1.自动化测试工具介绍 由于系统前后端分离,所以接口测试势在必行,在接触了几天接口测试框架,包括postman.httpclient.loadrunner.soapUI等,下面具体讲讲最终决定使用so ...
- 《手把手教你》系列技巧篇(二十七)-java+ selenium自动化测试- quit和close的区别(详解教程)
1.简介 尽管有的小伙伴或者童鞋们觉得很简单,不就是关闭退出浏览器,但是宏哥还是把两个方法的区别说一下,不然遇到坑后根本不会想到是这里的问题. 2.源码 本文介绍webdriver中关于浏览器退出操作 ...
- 《手把手教你》系列技巧篇(二十五)-java+ selenium自动化测试-FluentWait(详细教程)
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...
- 《手把手教你》系列技巧篇(六十四)-java+ selenium自动化测试 - cookie -中篇(详细教程)
1.简介 今天按照原计划宏哥要用实例来给小伙伴或童鞋们来演示一下,如何利用cookie实现跳过验证码进行登录.这个场景是自动登陆.有很多系统的登陆信息都是保存在cookie里的,因此只要往cookie ...
- 《手把手教你》系列基础篇(七十八)-java+ selenium自动化测试-框架设计基础-TestNG依赖测试- 中篇(详解教程)
1.简介 上一篇讲解了依赖测试的各种方法,今天继续讲解依赖测试的方法,这一篇主要是讲解和分享通过xml文件配置组名依赖方法( 主要是测试组的用法).废话不说,直接上干货. 2.实例 测试组:一个组可包 ...
- 《手把手教你》系列基础篇(八十三)-java+ selenium自动化测试-框架设计基础-TestNG测试报告-下篇(详解教程)
1.简介 其实前边好像简单的提到过测试报告,宏哥觉得这部分比较重要,就着重讲解和介绍一下.报告是任何测试执行中最重要的部分,因为它可以帮助用户了解测试执行的结果.失败点和失败原因.另一方面,日志记录对 ...
- 《手把手教你》系列基础篇(八十五)-java+ selenium自动化测试-框架设计基础-TestNG自定义日志-下篇(详解教程)
1.简介 TestNG为日志记录和报告提供的不同选项.现在,宏哥讲解分享如何开始使用它们.首先,我们将编写一个示例程序,在该程序中我们将使用 ITestListener方法进行日志记录. 2.Test ...
随机推荐- Convert Sorted List to Binary Search Tree [LeetCode]
Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...
- CSS hack方式一览【转】
做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我们会极不情愿的使用这个不太友好的方式来达到大家要求的页面表现.我个人是不太推荐使用hack的,要知道 ...
- django如何检查创建的模型(model)是否有语法错误或者逻辑错误
首先,用下面的命令验证模型的有效性: python manage.py validate validate 命令检查你的模型的语法和逻辑是否正确. 如果一切正常,你会看到 0 errors found ...
- Bat命令知识[转]
基础部分: 一.基础语法: 1.批处理文件是一个".bat"结尾的文本文件,这个文件的每一行都是一条DOS命令.可以使用任何文本文件编辑工具创建和修改. 2.批处理是一种简单的程序 ...
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第四步--地图循环&;amp;主角加入动作
说明:这里是借鉴:晓风残月前辈的博客,他是将泰然网的跑酷教程,用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...
- 原生js 函数 callee属性
一.在es5中,函数中有arguments参数,该参数是一个包含函数传入的参数的类数组. <script> function myArrgu(x){ console.log(argumen ...
- IDEA的Maxcomputer Studio开发
一.安装 在IDEA中File > Settings > Plugins中Browse repositories搜索安装即可:MaxCompute Studio 二.开发UDF.UDAF. ...
- CLR via C#关于泛型(Generics )的摘录
泛型,是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”. 简单的说,开发人员先定义好一个算法,比如排序.搜索.交换.比较或者转换等.但是,定义算法的开发人员并不设改算法 ...
- Linux系统服务之inetd
[Linux系统服务之inetd] inetd的角色是作为Telnet和FTP等与网络服务器相关的进程的“超级服务器”.这是一个简单的道理:并不是全部的服务器进程(包括那些接受新的Telnet和FTP ...
- 无法在web服务器下启动调试
VS2013 编译时异常 无法在web服务器下启动调试.该Web服务器未及时响应 VS2013 编译时错误 无法在web服务器上启动调试.该Web服务器未及时响应.无法在web服务器上启动调试.该 ...
手把手教你接口自动化测试 – SoapUI & Groovy Posted on 2015-01-21 09:38 WadeXu 阅读(12741) 评论(10) 编辑 收藏 手把手教你接口自 ...
要说android的自动化,那真是折腾死我了,从早期的monkeyrunner,到后来的robotium,再到最新的uiautomator,各有各的问题,总之性价比都不够高,不太适合我的使用场景.于是 ...
1.自动化测试工具介绍 由于系统前后端分离,所以接口测试势在必行,在接触了几天接口测试框架,包括postman.httpclient.loadrunner.soapUI等,下面具体讲讲最终决定使用so ...
1.简介 尽管有的小伙伴或者童鞋们觉得很简单,不就是关闭退出浏览器,但是宏哥还是把两个方法的区别说一下,不然遇到坑后根本不会想到是这里的问题. 2.源码 本文介绍webdriver中关于浏览器退出操作 ...
1.简介 其实今天介绍也讲解的也是一种等待的方法,有些童鞋或者小伙伴们会问宏哥,这也是一种等待方法,为什么不在上一篇文章中竹筒倒豆子一股脑的全部说完,反而又在这里单独写了一篇.那是因为这个比较重要,所 ...
1.简介 今天按照原计划宏哥要用实例来给小伙伴或童鞋们来演示一下,如何利用cookie实现跳过验证码进行登录.这个场景是自动登陆.有很多系统的登陆信息都是保存在cookie里的,因此只要往cookie ...
1.简介 上一篇讲解了依赖测试的各种方法,今天继续讲解依赖测试的方法,这一篇主要是讲解和分享通过xml文件配置组名依赖方法( 主要是测试组的用法).废话不说,直接上干货. 2.实例 测试组:一个组可包 ...
1.简介 其实前边好像简单的提到过测试报告,宏哥觉得这部分比较重要,就着重讲解和介绍一下.报告是任何测试执行中最重要的部分,因为它可以帮助用户了解测试执行的结果.失败点和失败原因.另一方面,日志记录对 ...
1.简介 TestNG为日志记录和报告提供的不同选项.现在,宏哥讲解分享如何开始使用它们.首先,我们将编写一个示例程序,在该程序中我们将使用 ITestListener方法进行日志记录. 2.Test ...
- Convert Sorted List to Binary Search Tree [LeetCode]
Given a singly linked list where elements are sorted in ascending order, convert it to a height bala ...
- CSS hack方式一览【转】
做前端多年,虽然不是经常需要hack,但是我们经常会遇到各浏览器表现不一致的情况.基于此,某些情况我们会极不情愿的使用这个不太友好的方式来达到大家要求的页面表现.我个人是不太推荐使用hack的,要知道 ...
- django如何检查创建的模型(model)是否有语法错误或者逻辑错误
首先,用下面的命令验证模型的有效性: python manage.py validate validate 命令检查你的模型的语法和逻辑是否正确. 如果一切正常,你会看到 0 errors found ...
- Bat命令知识[转]
基础部分: 一.基础语法: 1.批处理文件是一个".bat"结尾的文本文件,这个文件的每一行都是一条DOS命令.可以使用任何文本文件编辑工具创建和修改. 2.批处理是一种简单的程序 ...
- cocos2d-x 3.0游戏实例学习笔记 《跑酷》第四步--地图循环&;amp;主角加入动作
说明:这里是借鉴:晓风残月前辈的博客,他是将泰然网的跑酷教程,用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写,并做相关笔记 ...
- 原生js 函数 callee属性
一.在es5中,函数中有arguments参数,该参数是一个包含函数传入的参数的类数组. <script> function myArrgu(x){ console.log(argumen ...
- IDEA的Maxcomputer Studio开发
一.安装 在IDEA中File > Settings > Plugins中Browse repositories搜索安装即可:MaxCompute Studio 二.开发UDF.UDAF. ...
- CLR via C#关于泛型(Generics )的摘录
泛型,是CLR和编程语言提供的一种特殊机制,它支持另一种形式的代码重用,即“算法重用”. 简单的说,开发人员先定义好一个算法,比如排序.搜索.交换.比较或者转换等.但是,定义算法的开发人员并不设改算法 ...
- Linux系统服务之inetd
[Linux系统服务之inetd] inetd的角色是作为Telnet和FTP等与网络服务器相关的进程的“超级服务器”.这是一个简单的道理:并不是全部的服务器进程(包括那些接受新的Telnet和FTP ...
- 无法在web服务器下启动调试
VS2013 编译时异常 无法在web服务器下启动调试.该Web服务器未及时响应 VS2013 编译时错误 无法在web服务器上启动调试.该Web服务器未及时响应.无法在web服务器上启动调试.该 ...