qileilove

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

Java Web并发单元测试摘记(1)

  大的web项目开发和运行环境都在服务器容器中进行为主,包括调试过程,也都是单例进过Web触发进行测试。在Web项目中设计使用Spring、hibernate、JBPM工作流、ehcache各种框架或组件。这些东西在一起配置好一个有效的、覆盖所有环境的单元测试用例也比较复杂。所有配置好一个可用有效的单元测试环境十分必要。并且面对单元测试对并发要求的不支持,还得加入必要的并发测试组件,满足测试全面系统白盒测试要求。
  这里总结几种有效的配置单元测试方式:
  1、直接使用Junit4组件,进行简单单元测试,在setUp()中初始化各种测试环境如下:
@Override
protected void setUp() throws Exception {
super.setUp();
String[] paths = { "classpath:applicationContext.xml" };
ApplicationContext ctx = new ClassPathXmlApplicationContext(paths);
SpringContextListener.setApplicationContext(ctx);
// ############模拟servlet容器启动,手动更改配置文件路径
Constant.CURRENT_PROJECT_PATH = "src/";
// ############直接容器中获取bean
userManager = (UserManager) ctx.getBean("userManager");
userService = (UserService) ctx.getBean("userService");
}
  2、使用Sprint-test.jar框架,支持事务可注解方式启动的单元测试:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
@TransactionConfiguration(transactionManager="transactionManager",defaultRollback=false) //true将会回滚所有操作,默认没有该注解为回滚
public class JBPMProcessTest2 extends  AbstractTransactionalJUnit4SpringContextTests{
  以上都只能暂时支持简单功能的单元测试。但是要测试并发和压力等。需要加入一个常用的框架,支持在单元测试中注入多线程和并发。
  具体参见:http://blog.csdn.net/zhangyaoming2004/article/details/7619489 下面附有Jar包下载 http://yunpan.cn/QUtVay66VnU4T


 我们具体使用的功能不是很多,这些并发测试可以嵌入到上面两种单元测试方式中:如下:
/**
*
*/
package com.dtsz.model.service.test;
import net.sourceforge.groboutils.junit.v1.TestRunnable;
import com.dtsz.model.entity.report.common.InvokeSource;
import com.dtsz.model.service.ExcelReportLogicService;
import com.dtsz.model.service.TaskLogicService;
import com.dtsz.model.util.ExcelReportUtil;
import com.dtsz.view.vo.authenticator.UserVO;
import com.dtsz.view.vo.webservice.ExcelReportResult;
/**
* 模拟插件端数据上报的并发操作测试
*
* @author xiaoli
*
*/
public class CreateMulltiTaskReportGroboThread extends TestRunnable {
TaskLogicService taskLogicService;
ExcelReportLogicService excelReportLogicService;
private String reportMap;
private UserVO user;
private InvokeSource invokeSource;
private String bbq;
public CreateMulltiTaskReportGroboThread(String reportMap, UserVO user, InvokeSource invokeSource,String bbq) {
super();
this.reportMap = reportMap;
this.user = user;
this.invokeSource = invokeSource;
this.bbq = bbq;
init();
}
public void init() {
taskLogicService = (TaskLogicService)ExcelReportUtil.getBean("taskLogicService");
excelReportLogicService = (ExcelReportLogicService)ExcelReportUtil.getBean("excelReportLogicService");
}
/*
* (non-Javadoc)
*
* @see net.sourceforge.groboutils.junit.v1.TestRunnable#runTest()
*/
@Override
public void runTest() throws Throwable {
// TODO Auto-generated method stub
// ########################模拟当前任务该报表期任务上报
//保存数据
ExcelReportResult result = taskLogicService.reportData(reportMap, user, invokeSource);
excelReportLogicService.saveData(result);
System.out.println("报表期为:"+this.bbq+"已上报");
}
}
  单元测试并发:
/**
*
*/
package com.dtsz.model.service.test;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import junit.framework.TestCase;
import net.sourceforge.groboutils.junit.v1.MultiThreadedTestRunner;
import net.sourceforge.groboutils.junit.v1.TestRunnable;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.dtsz.model.entity.authenticator.User;
import com.dtsz.model.entity.report.common.InvokeSource;
import com.dtsz.model.service.authenticator.UserManager;
import com.dtsz.model.service.authenticator.UserService;
import com.dtsz.model.service.exception.BaseAppException;
import com.dtsz.model.util.BeanUtil2;
import com.dtsz.model.util.Constant;
import com.dtsz.model.util.Encryption;
import com.dtsz.view.util.SpringContextListener;
import com.dtsz.view.vo.authenticator.UserVO;



/**
* 模拟数据上报,这里的初始化数据根据插件端传入数据组合来的,当前只有根据报表期生成初始化数据
*
* @author xiaoli
*
*/
public class CreateMultiTaskReportTest3 extends TestCase {
private UserManager userManager;
private UserService userService;
@Override
protected void setUp() throws Exception {
super.setUp();
String[] paths = { "classpath:applicationContext.xml" };
ApplicationContext ctx = new ClassPathXmlApplicationContext(paths);
SpringContextListener.setApplicationContext(ctx);
// ############模拟servlet容器启动,手动更改配置文件路径
Constant.CURRENT_PROJECT_PATH = "src/";
// ############直接容器中获取bean
userManager = (UserManager) ctx.getBean("userManager");
userService = (UserService) ctx.getBean("userService");
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
@Test
public void test(){
// ###########自动生成报表期串集合
List<String> bbqs = new ArrayList<String>();
UnitTestUtils.imitateCreateMultiBbq(bbqs, 2, "2048", "5");
// 创建线程
TestRunnable[] tr = new TestRunnable[bbqs.size()];
int processCount = 0;
// ##########对这些数据进行填报
for (String bbq : bbqs) {
// 模拟上报数据
String reportMap = "{taskID:\"402880ee425a92f501425aa75ad50002\",bbq_:\""
+ bbq
+ "\""
+ ",bbhid:\"402855b942099b1b014209b1177e03f5\",approvalFlag:2,reportFlag:False,auditFlag:False,sheetMap:"
+ "[{id:\"402880ee425a92f501425aa75ad60004\",sheetType:\"BASIC\",values:{}}]}";
// 模拟上报的user
UserVO user = null;
try {
user = checkUser("xl1", "1");
} catch (BaseAppException e) {
e.printStackTrace();
} // 模拟插件端checkUser
String sessionInfo = "{institutionname:\"南昌分行\",institutioncode:\"A01NC\",username:\"肖力1"
+ "1\",usercode:\"xl1\",rolecode:\"null\",bbhId:\"402855b942099b1b014209b1177e03f5\",bbhcode:\"B01b\",btype:\"BASIC\",taskid:\"402880ee425a92f501425a"
+ "a75ad50002\",bbhname:\"基层财务b\",bbq:\"" + bbq
+ "\",frequency:\"MONTH\",SESSIONDIMENSION:{}}";
try {
userService.updateSession(sessionInfo, user);
} catch (BaseAppException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} // 模拟插件端updateSession
// 初始化上报方式
InvokeSource invokeSource = InvokeSource.WSCALL;
CreateMulltiTaskReportGroboThread reportThread = new CreateMulltiTaskReportGroboThread(reportMap,user, invokeSource,bbq);
tr[processCount] = reportThread;
processCount++;
}
System.out.println("#######################################计时开始########################");
long startTime = System.currentTimeMillis();
// 生成测试线程运行器
MultiThreadedTestRunner mttr = new MultiThreadedTestRunner(tr);
// 运行测试线程
try {
mttr.runTestRunnables();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("#######################一共耗时:"
+ String.valueOf((System.currentTimeMillis() - startTime) / 1000) + "秒");
}
/**
* xl1 1
* */
public UserVO checkUser(String userid,
String password) throws BaseAppException {
Map<String, String> paramMap = new HashMap<String, String>();
paramMap.put("UserName", userid);
paramMap.put("Password", password);
List<User> users = userManager.findByCodeCache(userid);
List<User> needUsers = new ArrayList<User>();
if (users != null && users.size() > 0) {
for (User user : users) {
if (user.getState() && user.getCode().equals(userid)
&& user.getPassword().equals(Encryption.encryption(password))) {
needUsers.add(user);
}
}
}
// 通过验证
if (needUsers != null && needUsers.size() > 0) {
User user = needUsers.get(0);
// 获取用户权限,并存放于session中
// UserVO userVO = userManager.getUserPermission(user.getId());
String ipAddress = "0.0.0.0";
UserVO userVO = new UserVO();
BeanUtil2.copyProperties(user, userVO);
userVO.setIpAddress(ipAddress);
return userVO; // 通过验证
} else {
return null;
}
}
}
  真实环境并发和压力测试不仅仅是在多个线程同时启动在测,还可能是增量式压力测试。这些还是要封装好和处理好。

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

开发环境及TTCN-3的Hello World

字体:        | 上一篇 下一篇 | 打印  | 我要投稿  | 推荐标签: 软件开发 TTCN

  本文一步一步介绍开发TTCN-3 Hello World程序的方方面面。
  博主的系统环境
  1、Windows XP SP3
  2、MS Visual C++ 2008,(对应IDE需要用到Visual的一个批处理文件)
  3、IDE:IBM Rational System Tester 3.3
  1,2两点就不说啦,IBM这个工具是个商用软件,分Windows版和Linux版的,相关主页在此:http://www-01.ibm.com/software/awdtools/ttester/
  3.3版本的还可以使用本地License文件,后续新版本的需要搭建一个局域网的License服务器,稍稍复杂一点。
  使用Tester开发,基本上是 TTCN-3完成测试脚步+C完成下层模块 的架构,Tester能对TTCN-3进行语法检查,再将TTCN-3脚步转成C语言代码,再对整个项目进行编译生成可执行文件。
  (lz支持采用正版软件,虽然我觉得IBM这个工具做得挺不好用的)
  上面是IDE成功安装后进入看到的界面。比较有帮助的是右下角的Project Samples,里面有大概10个例子,值得看看,依葫芦画瓢。
  我们目前从新建项目开始。
  依次选择File->New->Project->TTCN project,项目名称HelloWorld,一路Next,选择默认的项目配置即可
  完成后项目的结构图如下,分为两个文件夹,分别是ttcn与c文件


  右键HelloWorld.ttw,选择Settings配置,注意在Build中要添上vsvars32.bat的正确路径
  接下来在HelloWorld.ttcn文件中加入如下代码
module HelloWorld {
function Hello(){
log("Hello world !!");
}
control{
//直接打印hello world
log("Hello world !");
//通过函数调用打印hello world
Hello();
}
}
  接下来打开t3tri_template.c文件,搜索triSAReset()与 triPAReset()函数, 令函数返回TRI_OK
  然后点击菜单栏上的分析(小勾),编译(圆圈里面一个c),Build(两个下箭头),执行(感叹号)
  打印出如下结果
Running executable...
"Target\HelloWorld.exe"   -t3rt "+log -v 2 -lrtconf" -t3rt "-confbool t3rt.logging.builtin.pretty_print true"
Establishing connection with Test Management...
Connected to Test Management.
Telelogic Tester test suite started.
Waiting for commands ...
HelloWorld.ttcn (6): [CPC] scope_entered: control
HelloWorld.ttcn (8): [CPC] ttcn3_message: LOG Hello world !
HelloWorld.ttcn (11): [CPC] function_call: Hello() return <undefined>
HelloWorld.ttcn (2): [CPC] scope_entered: Hello() return <undefined>
HelloWorld.ttcn (3): [CPC] ttcn3_message: LOG Hello world !!
HelloWorld.ttcn (3): [CPC] scope_left: Hello() return <undefined>
HelloWorld.ttcn (11): [CPC] scope_left: control
[final] MESSAGE   Test case summary:
[final] MESSAGE
[final] MESSAGE   none          0 (0%)
[final] MESSAGE   pass          0 (0%)
[final] MESSAGE   inconc        0 (0%)
[final] MESSAGE   fail          0 (0%)
[final] MESSAGE   error         0 (0%)
[final] MESSAGE
[final] MESSAGE   total         0
  HelloWorld程序分析:
  上面就是在IBM工具中完成首个TTCN-3项目的流程,这个HelloWorld与其它语言比较起来还是略复杂的,但是从这个例子里面我们可以看出下面几点:
  1、TTCN的语言特性,module,模块是TTCN3中范围最大的单元(其他的都需要包含在Module中).
  一个Module包含两个部分:Module定义和Module控制,这两个部分都是可选的,也就是说一个Module中可以是空的,没有任何东西
  2、适配文件,例如本例子里面的两个c文件,光有TTCN-3代码是跑不起来的,需要将TTCN-3与下层代码联和编译才能执行
  3、结果打印:终端把一步一步的执行结果都打印出来了,最后还有测试的总结,TTCN系统是为测试而准备的。
相关文章:

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

TTCN-3 编码解码相关模块引入2

 在编解码例子一中提到了系统例子中提供的 binary_string.c,binary_string.h 两个操作二进制串的文件,看过代码的童鞋会发现,实现是使用一个char数组来保存数据的,也就是说,每次存入提取都需要以8比特为单位。
  在网络数据传输中一般是保证整字节的,但是网络协议的定义往往对每一比特位都“物尽其用”,因此在编解码的过程中往往会出现添加不是整字节单位数据的情况。
  考虑下面代码,使用到TTCN-3中hexstring的类型
module Codec_B {
//1.端口定义
type port common_port message {
inout all
}
//2.成分定义
type component MyMTC{
port common_port mtc_port;
}
type component MySUT{
port common_port sut_port;
}
// 定义测试
testcase Basic_TC () runs on MyMTC system MySUT
{
mtc_port.clear;
//不能操作sut_port,这个端口在SUT,并不在MTC的控制下
//sut_port.clear;
map(mtc:mtc_port, system:sut_port);
mtc_port.start;
//不能操作sut_port,这个端口在SUT,并不在MTC的控制下
//sut_port.start;
mtc_port.send('ABCD'H);
mtc_port.receive('ABCD'H);
mtc_port.send('ABC'H);
mtc_port.receive('ABC0'H);
setverdict(pass);
stop;
}
//控制部分
control {
execute(Basic_TC());
}
}



 编码函数中,碰到hexstring我们需要做出如下处理:
  1.碰到偶数情况与octetstring处理方式相同
  2.如果是奇数情况,需要额外多申请一个字节,该字节的高4位是数据、低4位用0填充;同时记录数据位数,继续编码时从低4位开始
  在binary_string.c 中添加处理半字节的方法
/* Appends half byte to the end of binary string
* It's assumed that binary string has enough free space
*/
static void append_half_byte (MyBinaryString *string, unsigned char data)
{
unsigned long free_pos;
free_pos = string->string.bits/8;
string->string.data[free_pos] = data;
string->string.bits += 4;
}
  在tci_codec.c中添加hexstring编码函数
//对hexstring类型的数据进行编码
void encode_hexstring(MyBinaryString *msg, String str)
{
unsigned char * binstr;
unsigned char binvalue;
unsigned long len;
int i,k;
printf("\n In function encode_hexstring() \n");
//输入的字符串中含有前后双引号和H,将它们去掉
len = str?strlen(str):0;
for(i=0;i<len-3;i++){
str[i]=str[i+1];
}
str[i]='\0';
len=strlen(str);//the new length
if(len%2==0){//偶数的话与处理octetstring相同
binstr =(unsigned char *)malloc(len);
char2hex_encode(msg,str,binstr);
binary_string_append_bytes(msg, binstr, len/2);
}else{
//基数的话先处理前面的偶数个字符
binstr =(unsigned char *)malloc(len);
//先把最后一个字符保存起来
binvalue = str[i-1];
str[i-1] = '\0';
char2hex_encode(msg,str,binstr);
binary_string_append_bytes(msg, binstr, len/2);
//处理最后一个字节,不够的用0填充
len += 1;
if(((binvalue-'0')>=0)&&((binvalue-'9')<=0)) {
binvalue = (binvalue-'0')*16;
} else if(((binvalue-'A')>=0)&&((binvalue-'F')<=0)) {
binvalue = (binvalue-'A'+10)*16;
} else if(((binvalue-'a')>=0)&&((binvalue-'f')<=0)) {
binvalue = (binvalue-'a'+10)*16;
} else {
tci_assert(0, "Wrong hex string: the value should be between 0~9, a~f");
}
binary_string_append_char(msg,binvalue);
}
printf("\n Leave function encode_hexstring() \n");
}
相关文章:
 TTCN-3 编码解码相关模块引入

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

自动化测试—关于自动化元素抽取

 为了能达到元素复用,以及后期维护的方便,按Activity划分,抽取每个Activity常用的控件到特定的类里,是一个比较好的方法
  如下截图所示,我用一个包来存放各个Activity要用到的控件
  看下ContactPanelElements 这个类里的内容:
  当我们要自动化某个用例的时候需要用到搜索框这个控件,我们只需通过ContactPanelElements.getSearchBarEditText就可以获得
  假如如果源码工程里的searchbar的id改了,我们也只需要修改 ContactPanelElements的id即可,不用去每个自动化用例里面去改
  有没有很便捷呢 ?

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

涉密信息系统测评的要点分析

 在涉密信息系统测评实践中,因测评人员对国家保密标准理解的差异性,导致在评价时存在不一致、不规范的情况。针对这种情况,山东省软件评测中心根据参与涉密信息系统测评工作的经验和认识,对如何评价涉密信息系统安全保密管理体系的有效性进行了分析,提出了测评时应注意把握的测评要点。
  1、应首先核实管理体系文件能否被执行
  在涉密信息系统测评中,涉密信息系统建设使用单位一般均会依据国家保密标准制定有关管理体系文件,并确定相关责任部门和人员。但其所建立的管理体系能否被执行,不能仅仅简单依靠涉密信息系统建设使用单位人员的情况介绍,而应要求建设使用单位提供证明。
  测评实践中一种情况是涉密信息系统建设使用单位能够提供成型的管理体系文件,但这些文件却并未经过正式发布确认,甚至还只是讨论稿。另一种况是有的单位虽然正式发布了安全保密管理体系文件,但发布的部门不具备相应权限,只能保证管理体系在本部门内被执行,无法保证管理体系在整个单位内被执行。此外,测评实践中发现,涉密信息系统建设使用单位往往将管理文件汇编并标定为涉密文件,按涉密文件进行管理,其印制的份数有限,也难于借阅。这样做虽然有利于对单位安全保密管理体系文件的保护,但同时也导致管理人员难以在需要时及时获得有关管理文件。
  2、应从全局角度确认管理体系的完整性
  对于已建立的管理体系,在核查其是否能够覆盖涉密信息系统安全保密管理的各个方面时,测评人员往往简单地从标准的各项具体条款入手,逐条查找相应的管理文件中是否设立了相应的规定。这种方式不仅操作繁琐,而且容易导致难以从全局的角度审视其管理体系的完整性。实际测评时应首先请涉密信息系统建设使用单位熟悉其安全保密管理体系的人员介绍管理体系文件的组成、相互关系、与保密标准的比对情况,之后再通过审视管理体系各个文件中所描述的适用范围,从全局的宏观角度确认其管理体系是否存在缺失。
  3、采用风险分析的方法来确认具体
  管理要求的合规性安全保密管理的具体要求与保密标准条款的符合性是系统测评时必须重点核查的内容。由于各项管理要求往往是根据涉密信息系统建设使用单位的具体情况制定的,若仅仅简单地核查管理要求的文字内容同标准中有关条款文字的符合性,则易于失去系统测评风险分析的本质,将合规性检查变成了文字核查。实际测评中,测评人员不仅要熟悉标准中各项条款的要求,更要明白各项要求中隐含的风险分析的思想与实质,采用风险分析的方法去判断各项管理要求同标准有关条款的符合性。
  对于具体管理要求的合规性判定,测评人员一方面要深入理解标准有关要求背后所涉及的风险;另一方面要学会采用风险分析的方法,在涉密信息系统建设使用单位管理人员的充分配合下进行综合分析,而不应拘泥于具体的文字表述。
  4、 应掌握评价管理制度可操作性的关键要素
  安全保密管理制度的可操作性是保证整个管理体系正常、有效运转的基础。实际测评中,可以从以下几方面考查相关管理制度的可操作性。
  4.1 是否明确了管理责任的主体
  任何一项管理制度首先应明确所规定的管理事项针对的责任主体,即谁对此项规定的执行负责。
  4.2 是否明确了管理的客体
  关于具体事务的管理规定中各条款一般均会涉及被管理的对象,即管理的客体。清晰、明确的管理客体,是该项制度可操作性强的重要前提。
  4.3 是否明确了操作的流程
  关于具体事务的管理规定中若仅仅是提出要求,而没有详细的操作流程,则实际操作中容易因操作人员的水平、安全保密意识等的差异导致操作结果不同,甚至出现严重的安全保密事故。


 4.4 是否明确了管理事项发生的具体时间、周期或触发条件
  保密标准中明确了必须定期开展的多项管理事项,但在涉密信息系统建设使用单位制定管理制度时,却很少结合自身情况确定开展相关事项的周期、时间或触发条件,这往往导致有关规定流于形式,不仅难以监督,而且还容易导致实际操作中必要环节的缺失。
  4.5 管理事项应可审计
  涉密信息系统由于安全保密管理失当导致出现安全保密事故,其结果往往存在影响大、责任重、处理严的特点。为杜绝出现安全保密管理责任事故、明确相关管理责任,也为发生事故后能够及时追查原因、减小事故造成的损失、定位责任人员或环节,以及提出合理的处理意见,必须加强涉密信息系统安全保密管理中重要事项、重点环节的审计。
  5、管理体系应能够自我改进
  涉密信息系统的安全保密管理不是一成不变的,而是随着技术的发展、网络结构的变化、用户的增减、人员安全保密认识的不断深入等情况动态变化的。涉密信息系统的安全保密管理体系只有具备了随着来自内部或外部的变化,不断自我适应、自我完善的能力,才能实现保护国家秘密这一最终目标。国家保密标准中也指出要通过分析异常事件、定期自评估和检查评估等手段,发现安全保密管理的薄弱环节并不断改进完善。因此,在测评实践中,要分析被测涉密信息系统的安全保密管理体系是否具备自我改进的能力,以防止在涉密信息系统开通运行一段时间后,出现安全保密管理体系与实际的管理需求不相适应的情况。
  6、结语
  本文根据中心参与涉密信息系统测评工作的经验和认识,就如何把握涉密信息系统安全保密管理的测评要点进行了讨论。由于在实际测评工作中,安全保密管理体系的评价存在较大的主观色彩,就本文中的不当之处,欢迎大家批评指正。
版权声明:本文出自山东省软件评测中心,51Testing软件测试网原创出品,未经明确的书面许可,任何人或单位不得对本文进行复制、转载或镜像,否则将追究法律责任。

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

性能测试流程各阶段的工作

 1.1 性能测试计划阶段
  测试计划阶段主要工作如下:
  1、明确测试对象
  2、定义测试目标
  3、定义测试通过的标准
  4、规划测试进度
  5、规划测试参与人员(需求、开发、测试、运维和配置)
  6、申请测试资源
  7、风险控制
  1.2 性能测试设计阶段
  测试设计阶段主要工作如下:
  1、测试用例设计
  2、测试方法设计(单场景和混合场景)
  3、定义监控指标,如测试性能指标以及性能计数器等
  1.3 性能测试实施阶段
  测试实施阶段工作如下:
  1、测试环境搭建
  2、测试过程文档定义以及配置
  3、测试脚本开发、调试
  4、测试数据准备
  5、基准测试
  1.4 性能测试执行阶段
  测试执行阶段工作如下:
  1、执行测试用例模型,包括执行脚本和场景
  2、测试过程监控,包括测试结果、记录性能指标和性能计数器的值
  1.5 性能测试结果分析和报告阶段
  <一>测试结果分析阶段工作如下:
  1、根据测试结果、记录性能指标和性能计数器的值进行测试分析
  2、根据性能测试目标规划,分析出系统存在的性能瓶颈,并给出优化建议
  <二>测试报告的内容包括如下:
  1、测试范围
  2、测试执行以及参与人员
  3、基准测试数据
  4、测试执行的详细步骤(场景设计)
  5、测试数据记录、性能指标以及性能计数器的值(有效的)
  6、测试结果对比以及总结性评价

posted @ 2013-12-02 09:31 顺其自然EVO 阅读(344) | 评论 (0)编辑 收藏

软件测试中一个智能的 Web 界面测试系统

  Web2.0 技术使 Web 界面更加丰富多彩,使信息交流更加灵活,同时也使得相关的 Web 技术测试需求越来越多。那么,如何提高 Web 界面的测试效率,保证新技术得到高质量应用?是否可以让测试人员脱离枯燥地点击鼠标,让机器自动地根据脚本运行?随着项目需求的变化,能否有一个比较快速地配置管理测试任务的方法?所有这些都可以通过一个智能的 Web 界面测试系统来实现。这个系统结合 TestNG, Ant, Selenium 还有 Flex 技术,实现方式简单、运行高效灵活,对单元测试功能测试和集成测试都有益,能够提高团队的工作效率。
  介绍 Web2.0 相关技术
  Web2.0 是一个体现当代 WWW 技术发展趋势的流行概念。它极力促进创造性、信息交互性以及用户间协作性的 Web 设计思想的推广。这些想法带来了各种丰富多彩的基于 Web 的互动和资讯服务的开发和演变。例如,社交网站,WIKI 以及博客。
  Web2.0 最突出的特色就是丰富的客户端技术。主要有三大类:
  Ajax 和 JSON
  Ajax(Asynchronous JavaScript + XML)是 Web2.0 的主要技术。网页浏览不再是单击一下,然后等待整个页面重新装载,而是可以用鼠标顺畅地滚动地图,等待局部数据的自动刷新。典型的事例应用是 Google Map。
  JSON(JavaScript Object Notation)是 Ajax 的衍生技术之一。Web 数据通常通过 XML 传输。而 JSON 对象是一系列以逗号分隔的 name:value 对,与 XML 相比更加的简洁,传输效率高,适合大规模数据传输。典型的应用事例是 Live Search Box。
  Restful
  REST(Representational State Transfer)是一种轻量级的面向数据库的 Web 服务架构。REST 架构遵循 CRUD 原则,对于资源只需要四种行为:Create(创建)、Read(读取)、Update(更新)和 Delete(删除)就可以完成对其操作和处理。典型的应用事例包括 Facebook 和 Flickr。
  RIA
  RIA(Rich Internet Application)是如今非常流行的 Web 技术。它的界面类似于一般的桌面程序,比一般的 Web 程序更加丰富并且互动。目前比较流行的技术有三项:Abobe Flex, 微软的 Silverlight 和 Sun 推广的 JavaFX。三种技术都有自己的 SDK 和开发工具。
  介绍测试系统流程
  以上我们简要介绍了 Web2.0 的概念和相关客户端技术。为确保客户端产品的质量,我们需要使用与此相应的 Web 测试工具,从而方便地融合于产品测试中。此外,为适应 Web 开发的灵活性,我们同时需要一个能够快速配置、部署、运行和汇报结果的测试系统,从而实现智能高效的测试流程,降低软件研发的成本。
  基于以上论述,下面将介绍一个智能的 Web 界面测试系统。该系统有四大模块组成,主体主要由 Python 语言实现,结合几种开发工具和技术,包括 Ant、Selenium、TestNG、XML 和 Flex。系统有两个控制方式:时间和 Web 管理站点。时间逻辑在 Python 脚本中实现,当时间到来时系统会按顺序下载源代码、部署应用程序、运行自动测试、发布报告;而 Web 管理站点通过 Flex 和 JAVA 技术来实现,用户可以按需在线配置某些模块,并要求立即执行自动测试。
  下面将详细介绍每个模块的具体工作内容。测试流程参见图 1。
  图 1. 测试系统概述
  源代码和安装包的按需下载
  在软件开发过程中,每天都会因新的功能而更改源代码。此外,很多项目需要国际团队合作,这些情况下代码的更新频率更加高。本土和国外团队经常需要共享源代码,而源代码可能被存放在固定的站点上面。当源代码文件量大而站点距离遥远的时候,下载代码的任务就比较耗时。为了节省这方面的时间,提高团队整体的工作效率,有必要让这部分工作自动化起来。所以,系统首先实现了一个结合 Python 和 XML 的下载控制模块。它的逻辑比较简单(参见图 2)。Python 程序定时读取配置文件,判断该任务当前是否可以运行。如果此刻时间和配置的时间一致,就访问站点,下载代码包。否则,放入等待队列,获取下一个任务。在等待队列里面的任务会在一定时间后重新启动。
  图 2. 下载流程

  下载配置文件的内容参见以下代码:
  清单 1.下载配置文件的代码
  读取下载配置文件的代码如下:
  清单 2.读取下载配置文件的代码
from xml.dom.minidom import parse, parseString
from MyDownloadTask import MyDownloadTask  def readFromProperty(xmlfile):
tasklist = []
dom = parse(xmlfile)
for node in dom.getElementsByTagName('item'):
name = node.getAttribute('name')
weekday = node.getAttribute('weekday')
time = node.getAttribute('time')
source = node.getAttribute('source')
target = node.getAttribute('target')
type = node.getAttribute('type')
// 定义一个下载任务
task = MyDownloadTask()
task.create(name, weekday, time, source, target, type)
// 加入下载任务列表
tasklist.append(task)
return tasklist
  实现具体的下载逻辑如下:
  清单 3.实现下载的代码
class MyDownloadTask(object):
…… // 定义一些变量
def create(self, name, weekday, time, source, target, type):
self.name = name
self.weekday = int(weekday)
self.source = source
self.target = target
index = time.find(":")
self.hour = int(time[0:index])
self.minute =  int(time[index+1:])
self.type = type
def run()
// 使用用户名和密码通过防火墙 password_mgr = urllib.request.HTTPPasswordMgrWithDefaultRealm()
password_mgr.add_password(None, self.source, username, password)
handler = urllib.request.HTTPBasicAuthHandler(password_mgr)
opener = urllib.request.build_opener(handler)
urllib.request.install_opener (opener)
// 从站点下载文件 content = urllib.request.urlopen(self. source).read()
f=open(self.target + self.buildno,"wb")
f.write(content)
f.close()
  此例指出目前有一项下载任务,下载类型是源代码,链接为 https://sample.sourcecode.com, 将其保持到 C 盘 sourcetar 文件夹下,时间为每天早上 7 点钟。(-1 代表任意时间)。项目组可以根据需要增加下载项。比如,我们项目组由于资源文件经常要修改,所以需要每天上午和下午都要检测是否有新的代码包,所以配置了两个下载任务。上午的时间一般都在 7 点,这样可以在每位同事上班打开电脑的那个时刻就获得大洋彼岸美国项目组下班时候的最新进展。
  正如前文所述,该测试系统中我们提供一个 Web 管理站点,用户可以根据项目的需要配置下载任务,不必麻烦系统管理员来修改下载配置文件。该模块使用 Flex 和 Java 技术实现(参见图 3)。用户可以通过它了解当前系统已有的下载任务。此外,用户也可以通过管理站点创建,修改和删除下载任务。这些更改最终都会被保存到 XML 配置文件中。
  图 3. 下载管理界面

应用程序的部署
  对 Web 应用程序而言,测试的第一步是部署。有了源代码后,测试系统使用 Ant 编写的脚本编译源代码,停止当前已有的 Web 服务器,部署产品代码,然后重新启动 Web 服务器。在这段时间中,产品的测试环境可能暂时无法访问(参见以下代码)。
  清单 4.代码部署
def deploybuild(self):
… // 清理文件夹,将源代码解压到 d 盘 buildtar 目录
try:
tar = tarfile.open(self.target + myHtml.srcbuild, "r:gz")
for tarinfo in tar:
print(tarinfo.name, "is", tarinfo.size, "bytes in size")
tar.extractall("d:/buildtar")
tar.close()
except :
// 编译源代码
os.chdir("d:/buildtar")
os.system("Ant all")
// 关闭 web 服务
os.system("net stop ”servicename"");
… // 部署系统
// 开启 web 服务
os.system("net start "servicename"")
  运行自动测试脚本
  当新版本的 Web 应用程序部署完后,测试系统就开始进入自动测试。本系统使用 SVN 对测试脚本进行版本控制。所以有必要在一开始通过 SVN 更新最近的测试脚本。这里使用 Ant 来调用 SVN 的命令行工具,参见下图。
  使用如下 Python 脚本调用相应的 Ant 任务:
  清单 5.Python 脚本
def runseleniumtestcase(self):
// 下载测试脚本
os.chdir("d:/")
os.system("Ant download-testcase -buildfile=task.xml")
// 运行测试脚本 os.chdir("d:/v510")
os.system("Ant start-selenium -buildfile=build.xml")                       
svn"/>
  事例中的任务 download-testcase 用来从站点 9.19.199.9 的 web/v100 目录下载最新版本的测试脚本。start-selenium 任务将启动 selenium 的 proxy server,然后按照 TestNG 配置的顺序运行测试脚本。
  测试系统的脚本应用 Selenium 和 TestNG 的测试工具,实现对各类型 Web 界面的测试需求。在第三节中将详细介绍 Selenium 工具在本系统的应用,并在第四章中介绍 TestNG 工具在配置 Selenium 测试脚本中的作用。
  为适应项目开发周期不同阶段的测试需求,Web 管理站点将列出当前所以测试案例。用户可以自由地挑选下次测试需要的用例。当用户选择保存后,这些测试脚本就会在下次系统自动部署时候被运行。如果用户选择运行,那么系统可以马上在当前已部署的产品环境上运行测试脚本。
  发布自动测试报告
  运行完自动测试用例后,测试结果自动生成于测试工具目录下面。这样会覆盖原先的文件,不利于项目的跟踪和信息的交流。所以,我们的测试系统会将测试报告发布到 Web 管理站点。用户只需按照上面的时间点击链接,就可以看到每次测试的运行结果(参见图 4)。
  图 4. 测试报告界面

posted @ 2013-12-02 09:30 顺其自然EVO 阅读(212) | 评论 (0)编辑 收藏

如何让LoadRunner实现多个场景运行?

  场景分析:
  有3个不同的场景,分别为搜索,下载,上传,其中3个场景执行顺序为按照搜索->下载->上传流程操作;哪么如何让Loadrunner中如何实现多个场景运行:
  方法1:利用Loadrunner中的Controller中的Vuser组模式
  注意:Vuser 组设置不适用于百分比模式。
  操作步骤:
  1. 打开Loadrunner Controller->选择“Manual Scenario”场景模式,添加脚本(Web_Search_100Vuser_15Mins_070401,Web_DownLoad_50Vuser_15Mins_070401,Web_UpLoad_50Vuser_15Mins_070401):
  2. 选择第1个脚本(Web_Search_100Vuser_15Mins_070401),点击“Edit Schedule”->选择“Schedule by Group”->点击“Scenario Start Time ”按钮,设置启动时间如下图所示:17:00:00 2007-4-24
  3. 选择第2个脚本“Web_DownLoad_50Vuser_15Mins_070401” ,点击“Edit Schedule”->选择“Schedule by Group”->在”Start Time”中选择”Start When group” Web_Search_100Vuser_15Mins_070401 Finihses, 点击”OK”确认
  4. 选择第3个脚本“Web_UpLoad_50Vuser_15Mins_070401”, 点击“Edit Schedule”->选择“Schedule by Group”->在”Start Time”中选择”Start When group” Web_DownLoad_50Vuser_15Mins_070401 Finihses,点击”OK”确认
  5. 选择“Results”-> “Results Settings”设置,如下图所示:
  6. 点击LoadRunner Controller中的“Start Scrnario”按钮,开始运行场景
  方法二:利用批处理命令操作
  (1)   打开LoadRunner controller设置场景(Web_Search_100Vuser_15Mins_070401,Web_DownLoad_50Vuser_15Mins_070401,Web_UpLoad_50Vuser_15Mins_070401),设置个场景的运行策略,然后保存文件
  (2)   设置3个场影的日志保存目录及名称,选择“Results”-> “Results Settings”设置:
  Website_Search_Result,Website_DownLoad_Result,Website_UpLoad_Result
  (3) 新建一个文本文件“website_night_070421”,编辑为以下内容:
SET LR_PATH="C:\Program Files\Mercury Interactive\Mercury LoadRunner\bin"
%LR_PATH%"wlrun.exe -TestPath "C:\Program Files\Mercury Interactive\Mercury LoadRunner\scenario\web_Search.lrs" -Run
%LR_PATH%"wlrun.exe -TestPath "C:\Program Files\Mercury Interactive\Mercury LoadRunner\scenario\web_Download.lrs" -Run
%LR_PATH%"wlrun.exe -TestPath "C:\Program Files\Mercury Interactive\Mercury LoadRunner\scenario\Web_UpLoad.lrs" –Run
  说明:要调用Loadrunner Controller,其实质是调用了wlrun,所以仅需在批处理命令中加入相应的语法格式即可,如上面所示:
  (4) 保存文件到C:\Program Files"Mercury Interactive"Mercury LoadRunner"scenario,并将文件放在场景文件中如下图所示:
  (5) 如果要执行多个场景的运行,只需双击运行”website_bat_night_070421.bat”文件
  注意事项:
  1. Loadrunner Controller 运行时总是会覆盖结果,所以需要设置好日志的保存目录及名称;
  2. 批处理运行脚本中的“-Run”中间未有空格;
  3. 批处理运行脚本中的参数区分大小写的。(如上面的脚本中Download当时写成了DownLoad死活不认,更改后才运行通过了)

posted @ 2013-12-02 09:21 顺其自然EVO 阅读(459) | 评论 (0)编辑 收藏

MonkeyRunner的长按操作实现

前两天组内一同事让我帮忙写个自动化脚本,操作很简单,就是打开测试页面中的各个链接,但有个特殊需求,就是点击链接过程中按下去之后要有一个60~100ms的延迟,之后才离开焦点。
  思考了一圈可用的开源工具后,感觉只有monkeyrunner最方便,因为已经有现成的方法(device.touch)和参数(DOWN_AND_UP)可用,但实际操作过程中发现,device.touch(100,100,'DOWN')并不是预期的一直按下状态。查看了monkeyrunner的源码后,看到DOWN,UP和DOWN_AND_UP都是MonkeyDevice下的方法,于是使用了这样的形式使用:device(100,100,MonkeyDevice.DOWN),测试成功。
  总结,MonkeyRunner的长按方式:
  device(100,100,MonkeyDevice.DOWN)
  MonkeyRunner.sleep(1)
  device(100,100,MonkeyDevice.UP)
  当然,也可以通过drag方法实现:device.drag((100,100),(100,100),1,10)
  两种方式效果一样,但实现原理是不同的,可以根据自己需求选择。
  附上帮助同事实现的脚本:
import random
from com.android.monkeyrunner import MonkeyRunner as mr
from com.android.monkeyrunner import MonkeyDevice as md
from com.android.monkeyrunner import MonkeyImage as mi
device=mr.waitForConnection()
#创建测试目录
device.press('KEYCODE_HOME','DOWN_AND_UP')
mr.sleep(1)
#打开新浪
device.touch(120,200,'DOWN_AND_UP')
mr.sleep(15)
url_x=55
url_y=200
#分别点击导航的各个链接
for i in range(1,19):
#长按实现方式
#device.drag((url_x,url_y),(url_x,url_y),0.2,1)
randomNum=random.uniform(0.06,0.1)
device.touch(url_x,url_y,md.DOWN)
mr.sleep(randomNum)
device.touch(url_x,url_y,md.UP)
print "sina:",i
print "sleep time:",randomNum
mr.sleep(15)
device.press('KEYCODE_BACK','DOWN_AND_UP')
url_x+=85
if url_x==480:
url_x=55
url_y+=45
else:
print 'end'
版权声明:本文出自 fjyxyz 的51Testing软件测试博客:http://www.51testing.com/?414422
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。

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

Java Application下读取properties配置文

 在java应用程序开发中,经常需要读取配置文件来获取系统参数或配置信息。配置文件可以使用xml格式文件,在java中存在.properties文件专门用作配置文件使用。在java中,类Properties用于处理配置文件相关的读取。下面是一个关于根据所提供的键获取值的示例。
public static String getvalue(String key)
{
Properties p=new Properties();
FileInputStream fis;
String url = new File("").getAbsolutePath() + File.separator+  "config.properties"; // 获取位于工程根目录下的config.properties配置文件绝对路径
try {
fis = new FileInputStream(url);
p.load(fis);
fis.close();
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.print("problems with properties");
e.printStackTrace();
}
return p.getProperty(key);
}

posted @ 2013-12-02 09:10 顺其自然EVO 阅读(316) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 175 176 177 178 179 180 181 182 183 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜