qileilove

blog已经转移至github,大家请访问 http://qaseven.github.io/

移动应用基本测试要点

移动应用基本测试要点:
  一、应用的功能
  ①注册登录:包含注册和登录的应用,需要测试注册和登录是否正常。
  ②数据显示:检测“更多应用”功能是否在正常工作。及点击“更多”是否会正常显示其他应用数据。
  ③互动分享:如果程序里面包括分享功能,那么检测点击分享的时候是否会正常给出分享提示,点击分享后所填写的分享内容是否正确
  ④内容下载:如果应用里面有内容下载,要检测内容下载连接是否在正常工作,即内容是否可以正常下载?解压?使用?
  ⑤软件版本检测:检测版本号是否正确?至少要比上一个版本多一个版本,例:当前版本1.0,那么下一个版本至少是1.0.1。程序启动后,是否正常检测版本更新提示。(对于Android,有提示则需要检测程序的更新下载是否正常)。
  ⑥辅助功能: 其他设置功能能否正常使用。
  ⑦离线使用:有离线功能的应用,在离线状态下,应用的功能使用是否正常,离线状态下相应的操作提示是否合理。
  ⑧离线后连接网络:离线后连接wifi或者2G,3G网络,基本功能能否正常使用。切换网络时是否会导致之前班级的内容消失或者错乱。切换网络经常会出现问题。
  二、应用的意外中断
  意外中断主要包括:电话、短信、挂起、低电量等
  在APP的不同的界面下面,接电话,挂起等,回到APP之后的应用是否异常。
  三、交互性测试
  ①数据同步功能:需要同步数据的应用,测试数据同步是否正常。
  ②点击程序里面的反馈是否会到指定的反馈页面,并且应用名称是否正确填写?
  ③内容型应用,点击单词的详细释义(未安装浏览器的手机),提示安装小d时是否闪退。
  四、应用的兼容性
  ①支持Android和ios的哪个版本;
  Android手机常见系统版本:1.5,1.6,2.0,2.1,2.2,2.3,4.0
  Android平板常见系统版本:3.0,3.1,3.2,4.0
  iPhone&iTouch&ipad常见系统版本:4.x,5.x
  ②分辨率的兼容性:测试应用在不同屏幕下的显示问题
  Android手机常见屏幕分辨率:240x320,320x480,480x800,480x854,540x960,640x960(其中240x320的屏幕现在应该很少见了)
  Android平板常见屏幕分辨率:1024x600,1024x768,1280x800
  iPhone&iTouch屏幕分辨率:320x480,640x960
  iPad屏幕分辨率:1024x768,2048x1536
 五、应用的性能
  ①应用的耗电量
  ②应用的流畅度
  六、网络测试
  ①3G上网:td-cdma、cdma2000、wcdma能否正常使用。
  ②edge、gprs能否正常使用(主要测试是否支持net接入点和wap接入点)
  ③应用的流量使用情况
  七、应用的内容测试
  ①内容型应用,上线前必须仔细核对检测内容是否有错误,音频是否不正常。
  ②检查内容型应用的内容是否包含非沪江信息
  八、最后一个版本需要测试下主体流程

posted @ 2013-11-06 10:26 顺其自然EVO 阅读(240) | 评论 (0)编辑 收藏

一款开源的自动化测试工具curl-loader

  最近发现一款新的性能测试工具,觉得对其进行一番研究和学习,下面是我从各个网站收集到的资料:
  第一章:安装介绍
  本期将推开性能测试工具LoadRunner,去研究一款开源性能测试工具Curl-Loader,关于两者的优劣我也不大清楚,不过对于Lr的强大,相信大家是领教多了,而理解性能测试的原理的话,对于Curl-Loader就可以溢于言表了。前者可以做录制,且业务逻辑复杂的流程;而后者更倾向于压力面的扩展,对于虚拟用户数的个数在单个机器上可以上到10000个以上。
  由于该工具运行于Linux平台,所以安装过程还是比较麻烦的,我们来看看Curl-Loaderde的安装如下:
  1、官方下载地址如下所示:
  http://sourceforge.net/projects/curl-loader/files/
  2、在官方网站上查看readme文档,以及FAST START文档,根据文档提示在安装之前先首先要了解系统是否具备了安装Curl-Loader的相关包,如下所示:
  openssl以及开发包这两个包是必须要安装的,一句官方提供的文档。
  3、具体安装方法如下:
$tar zxfv curl-loader-<version>.tar.gz
$cd curl-loader-<version>
$make
  安装完成之后在主目录中会生成curl-loader可执行文件,主要通过该命令来执行压力测试
  4、根据FAST START文档的说明,执行压力测试的过程可以通过conf-examples目录下的示例来解读,这里我们以10k.conf为例,配置如下:
########### GENERAL SECTION ################################
BATCH_NAME= 10K                                //这里是配置测试对象的名称
CLIENTS_NUM_MAX=10000                     //这里是配置最大虚拟用户数
CLIENTS_NUM_START=100                     //这里是配置初始化并发虚拟用户数
CLIENTS_RAMPUP_INC=50                      //这里是配置每次加载用户数
INTERFACE   =eth0
NETMASK=16                                        //子网掩码位数
IP_ADDR_MIN= 192.168.1.1                   //起始ip地址
IP_ADDR_MAX= 192.168.53.255            //最后的ip地址范围
CYCLES_NUM= -1
URLS_NUM= 1
########### URL SECTION ####################################
URL=http://localhost/index.html           //配置URL地址
#URL=http://localhost/ACE-INSTALL.html
URL_SHORT_NAME="local-index"
REQUEST_TYPE=GET
TIMER_URL_COMPLETION = 5000      # In msec. When positive, Now it is enforced by cancelling url fetch on timeout
TIMER_AFTER_URL_SLEEP =20
  配置完成之后就在命令下执行命令:./curl-loader -f 10K.conf,然后就开始执行压力测试。
  通过以上这个示例配置文件,可以清楚的理解这个就类似于LoadRunner中的场景设置页面,其实原理都一样。

 5、测试结果,在执行以上测试指令后,在命令窗口中就显示如下所示,具体的动态测试数据如下:
  在执行压力的时候显示如上页面,具体的参数就不一一详细介绍了,具体请参考官方FAQ文档,因为我也没有读完,只了解大概。
  在测试结束之后将会生成一系列的日志文件,详细测试信息还可以查看日志文件。
  第二章:学习视频
  1)开源性能测试工具Curl-Loader快速实战 - 1
  2)开源性能测试工具Curl-Loader快速实战 - 2
  3)开源性能测试工具Curl-Loader快速实战 - 3
  4)开源性能测试工具Curl-Loader快速实战 - 4
  开源性能测试工具Curl-Loader快速实战 (1)
  在线观看地址:http://www.boobooke.com/v/bbk1808
  下载地址:http://www.boobooke.com/v/bbk1808.zip
  开源性能测试工具Curl-Loader快速实战 (2)
  在线观看地址:http://www.boobooke.com/v/bbk1809
  下载地址:http://www.boobooke.com/v/bbk1809.zip
  开源性能测试工具Curl-Loader快速实战 (3)
  在线观看地址:http://www.boobooke.com/v/bbk1835
  下载地址:http://www.boobooke.com/v/bbk1835.zip
  开源性能测试工具Curl-Loader快速实战 (4)
  在线观看地址:http://www.boobooke.com/v/bbk1836
  curl-loader配置文件说明:
01
########### GENERAL SECTION ##################
02
BATCH_NAME= 10K-clients     #批处理名称
03
CLIENTS_NUM_MAX=10000       #虚拟客户端最大数量
04
CLIENTS_NUM_START=100       #虚拟客户端初始数量
05
CLIENTS_RAMPUP_INC=50       #虚拟客户端一次递增的数量
06
INTERFACE =eth0             #选择使工作的网卡
07
NETMASK=255.255.0.0         #子网掩码
08
IP_ADDR_MIN= 192.168.1.1    #模拟的ip开始地址段
09
IP_ADDR_MAX= 192.168.53.255 #模拟的ip结束地址段
10
CYCLES_NUM= -1              #每个客户执行的周期数不限
11
URLS_NUM= 1                 #每个客户得到单个url
12
13
########### URLs SECTION #######################
14
15
URL=http://localhost/index.html #待测目标的url
16
URL_SHORT_NAME="local-index"    #这个名字是url的代名词将被出现在负载开始时的
17
REQUEST_TYPE=GET                #请求类型
18
TIMER_URL_COMPLETION = 0        #url将使用http GET方法被提取且在时间上不受限制
19
TIMER_AFTER_URL_SLEEP = 0       #在完成一个url请求后进行下一个url请求的协议重定向的间隔时间
  运行curl-loader的基本命令为:
  curl-loader -f config.conf
  ,这个config.conf就是上面的配置文件具体的设置需要根据需要,我根据我的需求一开始把CLIENTS_NUM_MAX=设置为2000,CLIENTS_NUM_START为100,CLIENTS_RAMPUP_INC为50,意思就是说一开始的虚拟客户端就是100个,然后以每秒50个用户的速度递增一直达到最大值2000。
  因为是一开始运行测试,所以我没有设置的很大。为什么初始值不一开始就设置成2000呢,这个道理很简单,1,容易使被测的系统崩溃;2,不符合真实的环境;从这两方面考虑,所以要让压力的递增像一个爬坡的曲线慢慢的到到最大客户端值,也就是最大的压力然后保持一个稳定的范围,最后得到测试的参数再进行分析。在结束测试的时候我个人认为不用慢慢的递减压力,可以一下子把压力撤掉。
模拟的用户数量越多,占用的IP地址就越多,所以设置用户数量的时候要看IP_ADDR_MIN和IP_ADDR_MAX这两个参数间的IP个数是否满足,不满足的话要做适当的修改,可以大于等于,但不能小于,否则在运行
  #curl-loader -f config.conf
  的时候就会提示让修改配置文件参数的错误
  待测目标改成服务器端的IP地址即可,其他的暂时不用修改。
  在运行curl-loaderl之前最好要修改一下系统打开文件的最大值,因为用的是Linux系统而Linux系统默认可以打开最大的文件数为1024,所以要修改大点,一般要超过CLIENTS_NUM_MAX的值,修改命令为:
  #ulimit -n 10000
  注:后面的数值越大越好,最好是远远超过curl-loader虚拟的客户端数量;如果不修改就会出现the current limit of open descriptors for the shell (1024)类似的错误
  好了,终于不报错了,可以执行curl-loader运行命令了,没错,这样可以运行了,但还不是最好的状态,最好在加上一些运行的命令参数这样才能更大的发挥curl-loder的作用,也是测试结果更为准确
  下面就是各个参数的说明,是在官方网站找的,我全部按照自己的意思翻译了,这么简单的事情我Google,百度了半天竟然没有一个中文资源可以参考
  -c[onnection establishment timeout, seconds] :设置连接超时的时间
  -d[etailed logging; outputs to logfile headers and bodies of requests/responses. Good for text pages/files] :把header和bodies的反应等详细的情况输入到日志中。
  -e[rror drop client. Client on error doesn't attempt to process the next cycle] :如果虚拟客户端出现错误则在下一次的周期请求中不再尝试。
  -h[elp] :帮助
  -i[ntermediate (snapshot) statistics time interval (default 3 sec)] :设置最后一段状况的时间,默认是最后3秒。
  -f[ilename of configuration to run (batches of clients)] :设置想要加载的配置文件
  -l[ogfile max size in MB (default 1024). On the size reached, file pointer is rewinded(回滚) :设置日志文件的最大容量,默认是1024MB,当达到最大值时文件将会回滚覆盖从最旧的日期。
  -m[ode of loading, 0 - hyper (the default, epoll () based ), 1 - smooth (select () based)] :两种系统调用方式,epoll要优于select,但是也要测试为目的去选择。
  -r[euse connections disabled. Closes TCP-connections and re-open them. Try with and without]:不再重试继续连接,每次重试连接之前都会关闭之前的连接。防止连接缓存
  -t[hreads number. Use it for high loads and when running at SMP/multi-core HW] :用于高负载并且还是多核的cpu时,可以分配线程数。
  -v[erbose output to the logfiles; includes info about headers sent/received] :把headers的收发的详细情况输出到日志中。
  -u[rl logging - logs url names to logfile, when -v verbose option is used] :url日志,把url名字记录在日志文件中,当用-v选项时会被显示出来。
  -w[arnings skip] :跳过警告。
  可能有人觉得这么简单的英文直接自己看帮助或者man手册不就行了,太多的道理我也不想多说,我只想说翻译成中文这很重要!
  根据我的需求,首先-f指定配置文件,-l 10240MB增大日志文件,-m 0 选择epoll()调用方法这两种方法是在被测系统的内核里设置的所以这个选择最好要跟被测系统中的内核的选择一致这样才能测试的更准确,-r每次都是重新建立连接,-t 2 我安装curl-loader的机器是双核的这样可以更充分的利用系统资源使机器发挥出更大的作用,-u 记录url到日志中。所以我的curl-loader的运行命令就是:
  #curl-loader -f /home/user/10K/10K.conf -l 10240MB -m 0 -r -t 2 -u
  你会看到屏幕刷刷的翻动着,到后面会有一个最后三秒运行和总curr的状态
  如果想要结束测试ctrl+c就可以了
  下一篇我会写这些状态参数和结果的意义
  简单总结下我学习上面这些东西的过程:
  首先是在Google和百度上搜索中文资料,毕竟中文更易快速的理解,但是很失望,中文关于curl-loader的有价值的资料很少,大部分都是介绍怎么去安装,连配置文件的各个配置都没有一个能完全说明的,收获最多的就是看了网上流传的所谓的一个XX老师的教学视频,但是看到最后发现也不靠谱,curl-loader的测试结果里有个很重要的参数CAPS硬是给人胡说着解释出来了,当时就怀疑,随即到官网查看还真不是他说的那个意思,所以要怀疑一切所谓的权威,最好到官方的网站去找答案,即使是英文的。
  血汗泪的教训啊~,所以勇敢的站起来去大胆的怀疑权威,细心的去认证吧!
  还有,因为是刚开始写博客还搞不懂怎么把代码调成高亮显示,后面会改成高亮的那种
  下载地址:http://www.boobooke.com/v/bbk1836.zip
  第三章:深入学习

posted @ 2013-11-06 10:23 顺其自然EVO 阅读(293) | 评论 (0)编辑 收藏

Java从数据库中读取图片到Jpanel

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.Statement;
import java.sql.ResultSet;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.imageio.ImageIO;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
public class pictest
{
public pictest(){
JFrame f=new JFrame();
Container p=f.getContentPane();
ppic pic=null;
InputStream in=null;
try{
int i=3;
String url="****************";
Class.forName("com.mysql.jdbc.Driver");
Connection con=DriverManager.getConnection(url,"***","***");
//连接到数据库
if(!con.isClosed())
System.out.println("数据库连接成功");
String sql="select * from campusimage";
Statement st=con.createStatement();
ResultSet rs=st.executeQuery(sql);
for(int j=0;j<i;j++)
rs.next();
if(rs.next())
in=rs.getBinaryStream(1);
pic=new ppic(in);
rs.close();
st.close();
con.close();
}catch(Exception e){e.printStackTrace();}
p.setLayout(null);
p.add(pic);
f.setBounds(500,400,800,900);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class ppic extends JPanel
{   BufferedImage bi;
ppic(InputStream in){
try{
bi=ImageIO.read(in);
setBounds(0,0,700,600);
}catch(Exception e){e.printStackTrace();}
}
public void paint(Graphics g){
g.drawImage(bi,0,0,700,600,null);
}
}
public static void main(String[] args){
new pictest();
}
}
  ps:网上许多人都是把数据库中的图片实例化到本地,不仅读取速度慢,而且浪费内存,当时如果你的图片非常小就算了。

posted @ 2013-11-05 11:15 顺其自然EVO 阅读(412) | 评论 (0)编辑 收藏

查看Linux操作系统版本

 1. 查看内核版本命令:
chen@mylinuxserver:~> cat /proc/version
Linux version 2.6.5-7.244-smp (geeko@buildhost) (gcc version 3.3.3 (SuSE Linux)) #1 SMP Mon Dec 12 18:32:25 UTC 2005
/proc 目录的作用?
chen@mylinuxserver:/proc> uname -a
Linux mylinuxserver 2.6.5-7.244-smp #1 SMP Mon Dec 12 18:32:25 UTC 2005 i686 i686 i386 GNU/Linux
chen@mylinuxserver:/proc> uname -r
2.6.5-7.244-smp
  uname命令的作用?
  2. 查看Linux版本:
  1) 登录到服务器执行 lsb_release -a ,即可列出所有版本信息,例如:
chen@mylinuxserver:/proc> lsb_release -a
LSB Version:    core-2.0-noarch:core-3.0-noarch:core-2.0-ia32:core-3.0-ia32:graphics-2.0-ia32:graphics-2.0-noarch:graphics-3.0-ia32:graphics-3.0-noarch
Distributor ID: SUSE LINUX
Description:    SUSE LINUX Enterprise Server 9 (i586)
Release:        9
Codename:       n/a
  注:这个命令适用于所有的linux,包括Redhat、SuSE、Debian等发行版。
  2) 登录到linux执行cat /etc/issue,例如如下:
  chen@mylinuxserver:/proc> cat /etc/issue
  Welcome to SUSE LINUX Enterprise Server 9 (i586) - Kernel \r (\l).
  3) 登录到linux执行cat /etc/redhat-release ,例如如下:
chen@mylinuxserver:/proc> cat /etc/*release*
LSB_VERSION="core-2.0-noarch:core-3.0-noarch:core-2.0-ia32:core-3.0-ia32"
cat: /etc/lsb-release.d: 是一个目录
SUSE LINUX Enterprise Server 9 (i586)
VERSION = 9
PATCHLEVEL = 3

posted @ 2013-11-05 11:15 顺其自然EVO 阅读(247) | 评论 (0)编辑 收藏

使用JMeter进行HTTP负载测试

 在本文中,我将介绍一些如何用 JMeter 来进行 HTTP 负载测试的基础知识。JMeter 是一个java应用程序,用于模拟产生一个 高负载到一个服务器上,以测试这个服务器的承载强度,或用于分析在不同的负载下的服务器的性能。完整的 JMeter 情况,请到其官方网站上了解: 这里。
  你要明白的一件事是,这个工具并不是一个浏览器。这意味着 JMeter 并不会执行提供给浏览器执行的所有功能,它也无法运行 JavaScript 或 Flash。它只是一个能运行在 windows 上或其它操作系统上的一个桌面应用程序。因此,请首先到这里 把它下载下来。如果你使用的是 windows 操作系统,解压后你就可以运行“bin/jmeter.bat”命令来启动它。你将看到下面的显示:
  在本文中,我将介绍如果在 JMeter 中设置一个最基本的负载测试计划。一般来说,你想通过负载测试来获得以下两个问题的答案:
  - 你的应用程序能够承载多大的用户量?
  - 在什么样的负载下,你的应用会崩溃?
  因此,一开始,首先你要添加一个线程组(用户数):
  然后,开始设置这个线程组:
  - 用户数
  - 过渡期 (用户组发出请求的间隔时间)
  - 循环次数 (这个线程的运行次数)

 其次,你需要增加一个例程(HTTP 请求)到这个组中:
  一旦你增加了一个 HTTP 请求例程后,你将看到大量的选项。你需要注意的是:
  - 服务器名(Server Name) 或 IP
  - 路径(Path)
  定义完这个后,测试就准备好了,但我们通常需要一些测试报告。在 JMeter 中,我们称这种组件为监听器。因此,在这个测试计划中,加上一个监听器:



 你的全部的请求响应结果都将会显示在这里。按:Ctrl + R 开始运行这个测试。如果打开结果视图窗口(View Results Tree),你可以看到实时的运行状态。运行完后,你可以再按: Ctrl + E 来清除旧的结果,并重新按  Ctrl + R 来重新启动一次新的测试。最后,你可以看到类似以下的结果:
  正如我在一开始说的那样,这是一个最基本的 HTTP 负载测试计划。但 JMeter 提供的功能却远非如此简单,它能够通过建立大量的、你需要学习的各种选项来完成各种测试案例。我强烈推荐大家使用这个工具来进行各类测试。当然,这个工具用自定义插件来扩展也很简单。
  AtlantBH 开发了一套 JMeter 的扩展插件,包括:
  - OAuth Sampler
  - REST Sampler
  - JMS Tools (Java Request Sampler)
  - JSON 到 XML 转换器
  - XML Format Post-processor
  - HDFS Operations Sampler
  - HBase Scan Sampler
  - HBase RowKey Sampler
  - Hadoop Job Tracker Sampler
  - HBase CRUD Sampler
  - JSON utils (JSON Path Assertion, JSON Path Extractor, JSON Formatter)

posted @ 2013-11-05 11:11 顺其自然EVO 阅读(364) | 评论 (0)编辑 收藏

Linux 内存测试工具memtester

 下载地址:http://pyropus.ca/software/memtester/  有源码安装包、deb包、rpm包等。
  源码已经编译好,只要make一下就好了。
  使用方法:
  Usage: memtester [-p physaddrbase] <mem>[B|K|M|G] [loops]
  如:
  memtester 28G 3 #测试28G的内存3次。
  因为系统运行和本工具运行都需要内存,所以不能把所有的内存都测试到。可以先用free 命令查看系统剩余多少内存空间再测试。
  高级点的可以用-p参数从内存地址开始测试。
memtester version 4.2.0 (64-bit)
Copyright (C) 2010 Charles Cazabon.
Licensed under the GNU General Public License version 2 (only).
pagesize is 4096
pagesizemask is 0xfffffffffffff000
want 28672MB (30064771072 bytes)
got  28672MB (30064771072 bytes), trying mlock ...locked.
Loop 1/3:
Stuck Address       : testing   0memtester version 4.2.0 (64-bit)
Copyright (C) 2010 Charles Cazabon.
Licensed under the GNU General Public License version 2 (only).
pagesize is 4096
pagesizemask is 0xfffffffffffff000
want 28672MB (30064771072 bytes)
got  28672MB (30064771072 bytes), trying mlock ...locked.
Loop 1/3:
Stuck Address       : ok
Random Value        : ok
Compare XOR         : ok
Compare SUB         : ok
Compare MUL         : ok
Compare DIV         : ok
Compare OR          : ok
Compare AND         : ok
Sequential Increment: ok
Solid Bits          : ok
Block Sequential    : ok
Checkerboard        : ok
Bit Spread          : ok
Bit Flip            : ok
Walking Ones        : ok
Walking Zeroes      : ok
8-bit Writes        : ok
16-bit Writes       : ok
  结果全部为OK则内存正常。

posted @ 2013-11-05 11:11 顺其自然EVO 阅读(1063) | 评论 (0)编辑 收藏

个人总结—软件测试的目的

  软件测试的目的是以最少的人力、物力和时间找出软件中潜在的各种错误和缺陷,通过修正各种错误和缺陷提高软件质量,回避软件发布后由于潜在的软件缺陷和错误造成的隐患所带来的商业风险,一句话就是规避风险。
  一个好的测试用例在于发现从前未发现的错误;一个成功的测试是发现了从前未发现的错误的测试。 所以更为合适的定义是:测试是为发现错误而执行程序的过程。
  软件测试的目的是证明、检测、预防。
  证明:
  1)获取系统在可接受风险范围内可用的信心。
  2)尝试在非正常情况和条件下的功能和特性。
  3)保证一个工作产品是完整的且可用或可被集成的。
  检测:
  1)发现缺陷,错误和系统不足。
  2)定义系统能力和局限性。
  3)提供组件、工作产品和系统的质量信息。
  预防:
  1)通过将测试活动提前介入到软件生命周期中,尽早的发现并消除前期研发阶段引入的缺陷,以防止前期缺陷遗留并放大到后续环节。
  2)通过对发现的缺陷进行分析,找出导致这些缺陷产生的流程上的不足,通过改进流程,预防同类缺陷再次产生。
  对于如何处理测试中发现的错误,将直接影响到测试的效果。只有正确、迅速、准确地处理这些错误,才能消除软件错误,保证要发布的软件符合需求设计的目标。在实际软件测试过程中,对于每个Bug都要经过测试、确认、修复、验证等的管理过程。
  错误跟踪管理系统为了正确跟踪每个软件错误的处理过程,通常将软件测试发现的每个错误作为一条条记录输入制定的错误跟踪管理系统。
  缺陷跟踪管理软件在功能上各有特点,可以根据实际情况选用。当然,也可以自己开发缺陷跟踪软件。
  为一个缺陷跟踪管理系统,需要正确设计每个错误的包含信息的字段内容和记录错误的处理信息的全部内容。字段内容可能包括测试软件名称,测试版本号,测试人名称,测试事件,测试软件和硬件配置环境,发现软件错误的类型,错误的严重等级,详细步骤,必要的附图,测试注释。处理信息包括处理者姓名,处理时间,处理步骤,错误记录的当前状态。
  正确的数据库权限管理是错误跟踪管理系统的重要考虑要素,一般要保证对于添加的错误不能从数据库中删除。
  软件错误的状态新信息(New):测试中新报告的软件缺陷;打开 (Open):被确认并分配给相关开发人员处理;修正(Fixed):开发人员已完成修正,等待测试人员验证;拒绝(Declined):拒绝修改缺陷;延期(Deferred): 不在当前版本修复的错误,下一版修复关闭(Closed):错误已被修复;Bug管理的一般流程测试人员提交新的Bug入库,错误状态为New.高级测试人员验证错误,如果确认是错误,分配给相应的开发人员,设置状态为Open.如果不是错误,则拒绝,设置为Declined状态。
  开发人员查询状态为Open的Bug,如果不是错误,则置状态为Declined;如果是Bug则修复并置状态为Fixed.不能解决的Bug,要留下文字说明及保持Bug为Open状态。
  对于不能解决和延期解决的Bug,不能由开发人员自己决定,一般要通过某种会议(评审会)通过才能认可。
  测试人员查询状态为Fixed的Bug,然后验证Bug是否已解决,如解决置Bug的状态为Closed,如没有解决置状态为Reopen.软件错误流程管理要点为了保证错误的正确性,需要有丰富测试经验的测试人员验证发现的错误是否是真正的错误,书写的测试步骤是否准确,可以重复。
  每次对错误的处理都要保留处理信息,包括处理姓名,时间,处理方法,处理意见,Bug状态。
  拒绝或延期错误不能由程序员单方面决定,应该由项目经理,测试经理和设计经理共同决定。
  错误修复后必须由报告错误的测试人员验证后,确认已经修复,才能关闭错误。
  加强测试人员与程序员的交流,对于某些不能重复的错误,可以请测试人员补充详细的测试步骤和方法,以及必要的测试用例。

posted @ 2013-11-05 11:03 顺其自然EVO 阅读(173) | 评论 (0)编辑 收藏

Jmeter《Java请求》使用总结

1. 线程组,在我们测试方案里面,每个线程模拟一个用户,执行用户的登录、等等等一系列的操作。由于我们的项目是长连接的,如何能实现多个sample公用一个长连接客户端,考虑了很久,最后实现方法如下:
1 package tea.client.network;
2 /**
3  * @author Teaey
4  * @creation 2012-8-25
5  */
6 public class NetworkClientHolder
7 {
8     /**
9      * 这里使用ThradLocal存储BaseClient
10      * 方便一轮测试的每个sample都是由同一个socketChannel发送
11      * 更真实的模拟用户
12      */
13     private static ThreadLocal<BaseClient> clientHolder = new ThreadLocal<BaseClient>();
14     public static BaseClient getClient(String ip, String port)
15     {
16         BaseClient client = clientHolder.get();
17         if (null == client)
18         {
19             client = new BaseClient(ip, port);
20             client.connect();
21             clientHolder.set(client);
22         }
23         return client;
24     }
25 }
  代码中使用thread_local保存Socket客户端,这样每个sample中发送数据的客户端都是从这里拿的,就可以保证长连接的情况下,socket不会重复创建,很好的模拟了用户。
  当然不单单是链接可以保存,所有需要在线程中共享的数据都可以通过这种方法来实现。


  2. 接下来是如何封装发送请求的客户端,这里用的netty,具体可以根据项目情况使用mina或者nio都可以。代码直接明了^_^:
1 package tea.client.network;
2
3 import java.net.InetSocketAddress;
4 import java.util.concurrent.Executors;
5 import org.jboss.netty.bootstrap.ClientBootstrap;
6 import org.jboss.netty.channel.Channel;
7 import org.jboss.netty.channel.ChannelFuture;
8 import org.jboss.netty.channel.ChannelHandlerContext;
9 import org.jboss.netty.channel.ChannelPipeline;
10 import org.jboss.netty.channel.ChannelPipelineFactory;
11 import org.jboss.netty.channel.ChannelStateEvent;
12 import org.jboss.netty.channel.Channels;
13 import org.jboss.netty.channel.ExceptionEvent;
14 import org.jboss.netty.channel.MessageEvent;
15 import org.jboss.netty.channel.SimpleChannelHandler;
16 import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;
17 import tea.common.network.ClientDecoder;
18 import tea.common.network.ClientEncoder;
19 import tea.common.network.ClientMessage;
20
21 /**
22  * @author Teaey
23  * @creation 2012-8-25
24  */
25 public class BaseClient
26 {
27     public BaseClient(String ip, String port)
28     {
29         this.ip = ip;
30         this.port = port;
31     }
32     private String           ip;
33     private String           port;
34     private Channel          channel;
35     private ClientBootstrap  bootstrap;
36     private Object           syn             = new Object();
37     private static final int Receive_Timeout = 10000;       //ms
38     private ClientMessage    response        = null;
39     public void connect()
40     {
41         bootstrap = new ClientBootstrap(new NioClientSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
42         bootstrap.setOption("tcpNoDelay", true);
43         bootstrap.setPipelineFactory(new ClientPipelineFactory());
44         while (true)
45         {
46             ChannelFuture future = bootstrap.connect(new InetSocketAddress(ip, Integer.parseInt(port)));
47             future.awaitUninterruptibly(5000);
48             if (future.isDone())
49             {
50                 channel = future.getChannel();
51                 if (channel != null && channel.isConnected())
52                 {
53                     break;
54                 }
55             }
56         }
57     }
58     public void disconnect()
59     {
60         if (channel.isConnected())
61         {
62             channel.disconnect();
63         }
64     }
65     public boolean isConnected()
66     {
67         return channel.isConnected();
68     }
69     public void close()
70     {
71         if (this.channel.isOpen())
72         {
73             this.channel.close();
74         }
75         bootstrap.releaseExternalResources();
76     }
77     /**
78      * 发送消息,无需返回
79      */
80     public void send(ClientMessage message)
81     {
82         channel.write(message);
83     }
84     /**
85      * 发送消息,等待返回
86      */
87     public ClientMessage sendWaitBack(ClientMessage message)
88     {
89         response = null;
90         try
91         {
92             channel.write(message);
93             synchronized (syn)
94             {
95                 try
96                 {
97                     syn.wait(Receive_Timeout);
98                 } catch (InterruptedException e)
99                 {
100                     e.printStackTrace();
101                 }
102             }
103             if (null == response)
104             {
105                 System.err.println("Receive response timeout");
106             }
107         } catch (Exception e)
108         {
109             e.printStackTrace();
110         }
111         return response;
112     }
113     class ClientPipelineFactory implements ChannelPipelineFactory
114     {
115         public ChannelPipeline getPipeline() throws Exception
116         {
117             ChannelPipeline p = Channels.pipeline();
118             p.addLast("frameDecoder", new ClientDecoder());
119             p.addLast("fremeEncoder", new ClientEncoder());
120             p.addLast("logicHandler", new ClientMsgHandler());
121             return p;
122         }
123     }
124     class ClientMsgHandler extends SimpleChannelHandler
125     {
126         public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception
127         {
128             Object obj = e.getMessage();
129             if (obj instanceof ClientMessage)
130             {
131                 ClientMessage msg = (ClientMessage) obj;
132                 response = msg;
133                 synchronized (syn)
134                 {
135                     syn.notifyAll();
136                 }
137             }
138         }
139         public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
140         {
141             System.out.println("connected server:" + ctx.getChannel());
142         }
143         public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception
144         {
145             System.out.println("disconnected server:" + ctx.getChannel());
146         }
147         public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception
148         {
149             System.out.println("Error in exceptionCaught:" + e.getCause());
150         }
151     }
152 }
  这段代码展示了我们的客户端,这里所有的请求有两种发送模式,一种是发送并阻塞等待返回(sendWaitBack),第二种就是直接发送(send)。

  3. 有了发送请求的客户端,那如何能够更简单的实现一个协议好让客户端发送,再贴一段代码^_^:
1 package tea.client.network;
2
3 import org.apache.jmeter.config.Arguments;
4 import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
5 import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
6 import org.apache.jmeter.samplers.SampleResult;
7 import com.google.protobuf.InvalidProtocolBufferException;
8 import com.google.protobuf.MessageLite;
9
10 /**
11  * @author Teaey
12  * @creation 2012-8-25
13  */
14 public abstract class BaseSample extends AbstractJavaSamplerClient
15 {
16     public static final String PARAM_IP   = "ip";
17     public static final String PARAM_PORT = "port";
18     public static final String VAR_IP     = "${ip}";
19     public static final String VAR_PORT   = "${port}";
20     protected BaseClient       client;
21     public void addParameter(Arguments params)
22     {
23     }
24     /**
25      * Jmeter获取消息参数,默认配置ip和port两个参数
26      * 如果子类有更多参数,调用super.getDefaultParameters()获取Arguments后,继续设置其他方法
27      */
28     @Override
29     public Arguments getDefaultParameters()
30     {
31         System.out.println("1.getDefaultParameters");
32         Arguments params = new Arguments();
33         params.addArgument(PARAM_IP, VAR_IP);
34         params.addArgument(PARAM_PORT, VAR_PORT);
35         addParameter(params);
36         return params;
37     }
38     /**
39      * runTest的前置方法
40      */
41     @Override
42     public void setupTest(JavaSamplerContext context)
43     {
44         System.out.println("2.setupTest:" + context.containsParameter(PARAM_IP));
45         String ip = context.getParameter(PARAM_IP);
46         String port = context.getParameter(PARAM_PORT);
47         this.client = NetworkClientHolder.getClient(ip, port);
48         System.out.println("thread--->" + Thread.currentThread().getId() + " client--->" + client);
49     }
50     /**
51      * Jmeter调用,用于实际的测试
52      */
53     @Override
54     public SampleResult runTest(JavaSamplerContext context)
55     {
56         SampleResult sample = getSample();
57         sample.sampleStart();
58         try
59         {
60             MessageLite response = doTest();
61             String msg = response == null ? "" : response.toString();
62             sample.setResponseMessage(msg);
63             sample.setSuccessful(true);
64         } catch (Exception e)
65         {
66             sample.setSuccessful(false);
67             e.printStackTrace();
68         } finally
69         {
70             sample.sampleEnd();
71         }
72         return sample;
73     }
74     /**
75      * 获取本Sample的标签,子类实现
76      */
77     public abstract String getLabel();
78     /**
79      * 获取一个带标签的Sample
80      */
81     public SampleResult getSample()
82     {
83         SampleResult sample = new SampleResult();
84         sample.setSampleLabel(getLabel());
85         return sample;
86     }
87     /**
88      * Jmeter调用,用于
89      */
90     @Override
91     public void teardownTest(JavaSamplerContext context)
92     {
93         System.out.println("4.teardownTest");
94     }
95     /**
96      * 需实现,具体测试的方法,调用client的send/sendWithBack发送请求
97      * 如无返回,放回null即可
98      */
99     public abstract MessageLite doTest() throws InvalidProtocolBufferException;
100 }
  好的,这里封装了下AbstractJavaSamplerClient,每个消息默认包含ip和port参数,这可以再jmeter的用户变量中定义好。为了方便大家添加消息的参数,这里实现了空的
 addParameter(Arguments params)方法,这样在具体消息中直接重写这个方法,来添加具体的参数。是不是很方便?^_^,具体协议还需要实现的两个方法分别是:getLabel和doTest。第一个方法时用于报告显示的请求名字,一般定义为消息名字+“Label”就OKay。第二个方法就是我们重点重写的方法,这里再贴段代码,是一个具体消息的实现:
1 package tea.client;
2
3 import com.google.protobuf.InvalidProtocolBufferException;
4 import com.google.protobuf.MessageLite;
5 import tea.client.network.BaseSample;
6 import tea.common.network.ClientMessage;
7 import tea.common.network.RPC.HeartBeat_C2S;
8 import tea.common.network.RPC.HeartBeat_S2C;
9
10 /**
11  * @author Teaey
12  * @creation 2012-8-24
13  */
14 public class HeartBeatSample extends BaseSample
15 {
16     @Override
17     public MessageLite doTest() throws InvalidProtocolBufferException
18     {
19         HeartBeat_C2S.Builder request = HeartBeat_C2S.newBuilder();
20         request.setTimestamp(System.currentTimeMillis());
21         ClientMessage cm = new ClientMessage();
22         cm.setContent(request.build().toByteArray());
23         cm.setName("HeartBeat");
24         ClientMessage sm = client.sendWaitBack(cm);
25         HeartBeat_S2C response = HeartBeat_S2C.parseFrom(sm.getContent());
26         return response;
27     }
28     @Override
29     public String getLabel()
30     {
31         return "HeartBeatSample";
32     }
33 }
  可以看到doTest的工作就是封装请求,并拿到父类的client发送,然后返回响应(send方式返回null),Okay,大功告成。

posted @ 2013-11-04 13:17 顺其自然EVO 阅读(418) | 评论 (0)编辑 收藏

测试工具——Distcp工具深入分析

 引言
  DistCp命令是hadoop用户最常使用的命令之一,它位于hadoop tools包中,代码不多,约1300多行,主要用于在两个HDFS集群之间快速拷贝数据。DistCp工具代码结构清晰易懂,通过分析该工具的代码有助于我们更好的理解MR编程框架,并可以对hdfs文件系统有一个初步的了解。
  用法
  DistCp使用方法如下表所示:
OPTIONS:
-p[rbugp]              Preserve status
r: replication number
b: block size
u: user
g: group
p: permission
-p alone is equivalent to -prbugp
-i                     Ignore failures
-log <logdir>          Write logs to <logdir>
-m <num_maps>          Maximum number of simultaneous copies
-overwrite             Overwrite destination
-update                Overwrite if src size different from dst size
-f <urilist_uri>       Use list at <urilist_uri> as src list
-filelimit <n>         Limit the total number of files to be <= n
-sizelimit <n>         Limit the total size to be <= n bytes
-delete                Delete the files existing in the dst but not in src
  这里-p、-m、-overwrite都是常用参数,大多数情况下我们期望拷贝后数据权限保持一致,通过-p参数来完成权限一致性,拷贝并行度则由-m参数来调节。至于-overwrite往往和-delete合用,用来起到dst和src的一个diff功能。至于-update是很不靠谱的参数,因为只有当源和目标文件的大小不一致时distcp才会覆盖拷贝,如果大小一致,虽然内容不同distcp也依然会跳过这个文件不做拷贝。
  源代码与过程分析
  DistCp实现了org.apache.hadoop.util.Tool这个接口,这个接口实际只有一个有用的方法声明,即“int run(InputStream in, OutputStream out, OutputStream err,String... arguments);”通过ToolRunner这个类调度运行。
  DistCp解析完参数后,首先通过源路径检测并获得文件系统句柄。然后进入setup方法:
  private static void setup(Configuration conf, JobConf jobConf,
  final Arguments args)
  该方法是DistCp做准备工作的地方,首先是结合一个随机数生成一个工作目录,并将该目录路径作为参数传递给Mapper,在这个目录下会生成两个文件“_distcp_src_files”和“_distcp_dst_files”,这两个文件都是SequenceFile,即Key/Value结构的序列化文件,这里将记录所有需要拷贝的源目录/文件信息列表。其中_distcp_src_files 的key是源文件的size,如果是目录则记录为0,value是自己实现的Writable接口类FilePair,记录目标节点的org.apache.hadoop.fs.FileStatus和路径。_distcp_dst_files的key是目标路径,和节点的FileStatus。这两个文件是DistCp工具的关键点,在setup方法中,DistCp通过递归遍历了要拷贝的所有源头数据列表,生成了这两个文件。
  随后,DistCp会以268435456字节(256MB)为切分单位计算map数,这个数值可以通过-sizelimit参数进行人为修改。DistCp构造了自己的InputSplit,将_distcp_src_files文件以刚才所说的值为单位进行切分,如果设定了-m参数,则会按照该参数设定的map数为基准进行切分。这里需要注意切分的map数不会恰好等于-m参数设定的值,由于不能整除的原因,总会或多或少的偏离一点设定值。

 map数的确定算法如下:
private static void setMapCount(long totalBytes, JobConf job)
throws IOException {
int numMaps =
(int)(totalBytes / job.getLong(BYTES_PER_MAP_LABEL, BYTES_PER_MAP));
numMaps = Math.min(numMaps,
job.getInt(MAX_MAPS_LABEL, MAX_MAPS_PER_NODE *
new JobClient(job).getClusterStatus().getTaskTrackers()));
job.setNumMapTasks(Math.max(numMaps, 1));
}
  这里可以看到,DistCp其实还判断了集群实际tasktracker数量,防止map数设置的太多,导致很多map需要等待一轮轮的调度。
  切分代码如下:
SequenceFile.Reader sl = null;
try {
sl = new SequenceFile.Reader(fs, src, job);
for (; sl.next(key, value); last = sl.getPosition()) {
// if adding this split would put this split past the target size,
// cut the last split and put this next file in the next split.
if (acc + key.get() > targetsize && acc != 0) {
long splitsize = last - pos;
splits.add(new FileSplit(src, pos, splitsize, (String[])null));
cbrem -= splitsize;
pos = last;
acc = 0L;
}
acc += key.get();
}
}
finally {
checkAndClose(sl);
}
  split之后就进入Mapper执行阶段,map task起来后就会根据自己分配到的那段文件列表来进行点对点的拷贝,拷贝过程会保持Permission、Replication、Block Size的一致性,如果设定了-update则会做一下是否需要update的判断,如果设定了-overwrite则会删除已有的文件。这里Owner信息没有保持一致,而是放到了服务端所有map执行完之后,这一点很让我觉得纠结,为什么不在map里面拷贝完之后直接同步文件Owner呢?如果有哪位大师知道希望可以提点我一下。因为是实现了Tool接口,而Tool接口是继承了Configurable接口的,所以-D指定的值对于DistCp来说也是可以生效的。例如设定“-Ddfs.replication=1”,那么拷贝时目标文件的replication数就将保持为1,这样一来由于目标端需要写入的数据变少了,拷贝速度就可以大大加快,但是不推荐这么做,因为拷贝过程中如果有一台Datanode挂了,那么丢失的数据由于无备份,就将真正丢了,这台机器恢复不了的话,整个distcp过程就会因为丢数据而失败了。
 拷贝过程关键代码如下:
FSDataInputStream in = null;
FSDataOutputStream out = null;
try {
// open src file
in = srcstat.getPath().getFileSystem(job).open(srcstat.getPath());
reporter.incrCounter(Counter.BYTESEXPECTED, srcstat.getLen());
// open tmp file
out = create(tmpfile, reporter, srcstat);
// copy file
for(int cbread; (cbread = in.read(buffer)) >= 0; ) {
out.write(buffer, 0, cbread);
cbcopied += cbread;
reporter.setStatus(
String.format("%.2f ", cbcopied*100.0/srcstat.getLen())
+ absdst + " [ " +
StringUtils.humanReadableInt(cbcopied) + " / " +
StringUtils.humanReadableInt(srcstat.getLen()) + " ]");
}
} finally {
checkAndClose(in);
checkAndClose(out);
}
  Mapper执行完之后,DistCp工具的服务端执行过程就全部完成了,回到客户端还会做一些扫尾的工作,例如同步Owner权限。这里会有一些问题,稍后我们一并分析。
  问题分析
  DistCp存在三大问题,下面来一一剖析:
  1.任务失败,map task报“DFS Read: java.io.IOException: Could not obtain block”
  这是由于“_distcp_src_files”这个文件的备份数是系统默认值,例如hadoop-site.xml里面设置了dfs.replication=3,那么_distcp_src_files文件的备份数则创建之后就为3了。当map数非常多,以至于超过了_distcp_src_files文件三个副本所在datanode最大容纳上限的时候,部分map task就会出现获取不了block的问题。对于DistCp来说“-i”参数一般是绝对不能使用的,因为设置了该参数,这个问题就会被掩盖,带来的后果就是拷贝完缺失了部分数据。比较好的做法是在计算了总map数之后,自动增加_distcp_src_files这个文件的备份数,这样一来访问容纳上限也会跟着提高,上述问题就不会再出现了。当前社区已对此有了简单fix,直接将备份数设置成了一个较高的数值。一般说来对于计算资源有限的集群来说,过多的maptask并不会提高拷贝的效率,因此我们可以通过-m参数来设定合理的map数量。一般说来通过观察ganglia,bytes_in、bytes_out达到上限就可以了。
  2.Owner同步问题
  DistCp工具的提示信息非常少,对于海量数据来说,DistCp初始阶段准备拷贝文件列表和结束阶段设定Owner同步耗时都比较长,但却没有任何提示信息。这是一个很奇怪的地方,拷贝过程中,mapred会打印进度信息到客户端,这时候可以看到百分比,等结束的时候可以看到过程中的一些统计信息。如果你设置了-p参数,此时就会处于一个停滞的状态,没有任何输出了。由于Owner同步没有在map task里面去做,放在客户端就必然成为一个单线程的工作,耗时也会比较长。我以前犯过的错误就是启动distcp后看jobtracker页面出现作业了,就kill了客户端的进程,这样一来就导致Owner不会同步。现在做法都是用“nohup nice -n 0”把进程放到后台让其自动结束。
  3.长尾问题
  DistCp切分map的时候,充分考虑了每个map需要拷贝的数据量,尽量保持平均,但是却完全没有考虑碎文件和整块文件拷贝耗时不同的问题。此外,某些task所在tasktracker机器由于故障之类原因也会导致性能较差,拖慢了整体节奏。拷贝大量数据的时候总会因为这些原因出现长尾。通过在InputSplit的时候同时考虑数据量和文件个数的均衡可以解决碎文件和整文件拷贝耗时不同的问题。而部分task运行慢的问题,目前看起来则没有很好的解决方案。
  用途
  DistCp这个工具不仅可以用来做数据拷贝迁移工作,同时也是一个很好的制造集群负载的工具。用来模拟一定压力下的集成测试是非常有效的。在跨机房项目中,我们使用该工具负载两个机房之间的带宽,通过控制同时工作map数来调整带宽的增减是非常有效的。拓展该工具的代码思路,我们在跨机房项目中制作出来的很多压力测试、性能测试工具也都发挥了作用。下面简单用一幅流程图来说明一下distcp工具的思想:
  总结
  DistCp工具是一个非常易于使用的拷贝工具,在Hadoop生态圈众多怪兽级应用中,DistCp的代码是优美且短小精悍的。也因为其代码易读性非常好,因此作为MR编程框架的入门教材也非常适合。小心的使用这个工具,我们可以在很多测试场景下模拟真实的线上情况。因此建议每位刚入Hadoop门的码农都能钻研一下DistCp的源码,增加对MR编程框架和HDFS文件系统的深入理解。

posted @ 2013-11-04 13:13 顺其自然EVO 阅读(4100) | 评论 (0)编辑 收藏

LR 使用agent proess的几个问题

  新来了一批机子,打算用来做性能测试的负载机,安装好完整的LR程序后(可能有些人认为只安装agent proess程序就行了,但我还是安装了完整版的,避免出现一些未知的问题,反正花费的时间差不多),通过Contorller进行调用,在调用HTTP协议的代码时,一切顺利,但是调用JAVA代码时,遇到了一些问题,现总结如下:
  1. 启动 agent proess时,报如下错误
28/10/2013 14:55:06 Error: Communication error: Failed to bind socket while calling bind function.    [MsgId: MERR-10344]
28/10/2013 14:55:06 Error: Communication error: Failed to create a TCP server for the HTTP channel's server.    [MsgId: MERR-10344]
28/10/2013 14:55:06 Error: Two Way Communication Error: Function two_way_comm_create_acceptor failed.    [MsgId: MERR-60999]
28/10/2013 14:55:06 Warning: Failed to create "router" server.    [MsgId: MWAR-29974]
  可以不用去理会,不影响运行结果
  2. Contorller调用JAVA程序,在负载机上运行时,报如下错误:
  Error: Failed to open .eve file: "d:\lr_results\sw\smx\login\res\192.168.32.114_8.eve”
  这个是负载机环境的.NET环境有问题(谢谢MIKE的提醒),更新完最新的相关补丁后,解决!(360打补丁还是很好用的)
  3. 解决完问题2后,再次调用运行后,报如下错误:
  Compilation process failed
  最后的解决方案记录如下:
  在负载机上,把脚本中使用到的其它jar包或class文件,放到loadrunner安装路径下的classes目录下
  如:D:\Program Files\HP\LoadRunner\classes
  注意:如果import 时,调用的class文件,有路径,则放到classes时,也需要对应放置
  如:import com.seaway.test.CookieCallServer;
  那么,放到D:\Program Files\HP\LoadRunner\classes下的,也要为com.seaway\test\CookieCallServer;
  即,完整路径为:D:\Program Files\HP\LoadRunner\classes\com.seaway\test\CookieCallServer;
  问题解决!

posted @ 2013-11-04 13:12 顺其自然EVO 阅读(1209) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 187 188 189 190 191 192 193 194 195 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜