qileilove

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

单元测试等价于白箱测试吗?

  单元测试 = 白箱测试? 这是很多人的想法. 一听到白箱测试, 就认为他就是单元测试. 或者认为单元测试时, 就是要用白箱测试的方法来进行.
  事情是这样吗? 让我们继续看下去:
  当我们要测试这个程序时
  Stack push(Stack s, int key)
  你会怎么测试呢? 你可能会考虑以下几种状况
  (1) 空的 stack, 第一次 push
  (2) 不是空的 stack, 然后 push 东西
  (3) stack 是满的, push 个东西看会不会有问题
  (4) 不是空的 stack, 然后 push 一个字符
  (5) 不是空的 stack, 然后 push 一个指标
  你所做的大多是根据程序思考逻辑, 或者是根据输入的值域来做参考, 来建立测试个案.
  这些方式其实都是黑箱测试(用到了 use case testing 和 Equivalence Class Testing等方法, 可自行去网络上找详细介绍), 也就是不管程序内部如何被实作. 只根据行为和输入值域来开立测试.
  那真正的白箱测试会是怎么进行呢?
  基本上, 可以测试的状况有无限多种. 而白箱测试是要根据程序内容来决定要怎样挑最小可测试的集合.
  那程序内有甚么东西, 可以让我们来做挑选的判断呢? 一般常见的是根据程控逻辑. 例如: 是否经过所有的叙述(statement); 是否经过程序所有分支等等.
  如果以经过所有的叙述为例, 对于下面的程序
  01: Stack push(Stack s, int key)
  02: {
  03:     if(isFull(s)){
  04:        printf("Stack is full !!\n");
  05:     }else{
  06:         s.top = s.top + 1;
  07:         s.element[s.top] = key;
  08:         printf("Success push %d in the Stack\n", key);
  09:     }
  10:     return s;
  11: }
你会找出这组路径, 来当作最小需要测试的集合, 然后对它建立其相对应的测试个案
  path1: 01-02-03-05-06-07-08-09-10-11
  test case 1:
  push (s, 3)
  path2: 01-02-03-04-10-11
  test case 2:
  push (s, 3) (repeat 10 times, 如果 stack 大小是10 的话)
  push (s, 3)
  (当然你可以只用test case 2, 因为它涵盖了 test case 1 的状况)
  一般人通常不会先分析执行路径, 再找测试个案. 大多是根据一些准则, 找出测试个案就开始测试了. 所以一般单元测试是用黑箱测试方式在进行, 而非白箱测试.
  那为何大家会有错觉单元测试 = 白箱测试呢?
  那 是因为在进行白箱测试时, 对于一个大的系统要找出可执行路径, 会是一件很复杂的事情. 但是对于每个单元时, 这件事情变得比较容易, 比较有可能不藉由工具的辅助, 就能自己进行. 也就是说在单元测试时, 比较容易进行白箱测试. 可是不知怎么传的, 很多人就把这两个视为同义.

posted @ 2014-07-23 09:36 顺其自然EVO 阅读(167) | 评论 (0)编辑 收藏

好的黑盒测试方法应该是什么?

  很多测试人员会询问, 是否有一种测试方法, 可以很系统化地, 来开立所有测试个案.
  我也很期待有这种东西, 可惜一直没有看到, 不管哪种黑盒测试方法, 都有它的优点和缺点.
  更重要的是黑盒测试有个重大的致命点, 它是完全依赖测试人员的经验. 如果测试人员的产品领域知识, 以及产品所处的系统知识丰富, 就能开出更好的测试个案.
  例如: 等价分析法(Equivalence Class). 他要求先找出等价区域 (Partition or equivalence class),  然后对每个区域开出一个测试个案, 只要这些个案执行完, 就说测试完毕.
  但是有经验的测试人员, 他能找出的区域, 可能质量比没有经验的人好上百倍. 所以不管测试方法再好, 也需要有优秀的人才. 就像圆月弯刀中, 丁鹏杀了柳若松后说, "有些人纵有神刀在手, 仍是无法成为刀中之神的”.  资质永远是第一首选.
  可是如果资质不好, 就没有办法改变了?
  在一次对话中, 让我被启发了. 或许这些方法无法让你开出很完整的测试个案, 但是是否有方法, 让你清楚表达你的思考逻辑.  如果可以清楚表示, 别人或是自己就可以容易检查有没有缺陷或是遗漏.
  就这像用鱼骨图, mindmap, 或是 decision tree 等方式来呈现事情, 可以让别人看到后很快可以理解, 并且也可以很快地给你回馈. 所以同理, 好的黑盒测试方法, 应该也要具备相同的特质.
  因此根据这样的想法, 哪一种黑盒测试的方法比较合适呢? 目前看起来应该是 Decision Table Testing. 因为它会将你想的测试状况, 明确清楚的列出来, 这时候别人就可以检视你的思考逻辑. 以下是使用 decision table 测试方法的范例: 说明在这样的商业规则下, 你需要考虑哪些测试 scenario. 这样的表达方式, 别人可以快速知道你是怎么思考, 是否有不足的地方.
  所以我现在从找最好的测试方法, 改成找最容易表达你测试思维的方法. 这算是进步呢? 还是我很容易满足 ….

posted @ 2014-07-23 09:34 顺其自然EVO 阅读(209) | 评论 (0)编辑 收藏

自己实现的附带文件的压力测试方法

前段时间做了一个服务器端接口,是附带文件上传的;后来我们要对这个接口进行压力测试
  其实很多现成的方式可以做压力测试,但是附带文件的的压力测试缺不怎么符合我的需求,jmeter是可以做附带文件上传的压力测试的,只是它是图形界面,而我目前的需求是要在测试机器上面去跑测试,而测试服务器是不能带图形界面的,所以jmeter的方案否决掉;
  apache ab test,也是一个压力测试的好工具,只是研究了好久老搞不掂怎么做附带文件上传的压力测试(备注:在本文的最后我附带一下我研究的结果,说多了都是泪)
  好了,现在我说下我自己的这个测试工具:
  它依赖于赖于httpclient相关的包,包括:commons-codec-1.6.jar、commons-logging-1.1.3.jar、fluent-hc-4.3.4.jar、httpclient-4.3.4.jar、httpclient-cache-4.3.4.jar、httpcore-4.3.2.jar、httpmime-4.3.4.jar、httpmime-4.3.4.jar;
  大家可以到apache的官方网站:http://hc.apache.org/downloads.cgi  去下载相关的包;
import java.io.File;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
public class ClientMultipartFormPostTest {
private static ExecutorService pool = Executors.newFixedThreadPool(300);
public static void main(String[] args) throws Exception {
final String path = args[0];//文件地址
final String url = args[1]; //调用的URL
final int i_len = Integer.parseInt(args[2]);//线程总数
final int j_len = Integer.parseInt(args[3]);//每个线程的请求数(暂时没用到)
final AtomicInteger c = new AtomicInteger(0);
final long s = System.currentTimeMillis();
for (int i = 0; i < i_len; i++) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
upLoadLogMultiThread(url,path);
int cc = c.addAndGet(1);
if (cc % 1000 == 0) {
System.out.println(String.format("c: %d, t: %d", cc, (System.currentTimeMillis() - s)));
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
}
}
public static void upLoadLogMultiThread(String url,String path) throws IOException{
CloseableHttpClient httpclient = HttpClients.createDefault();
try {
HttpPost httppost = new HttpPost(url);
FileBody bin = new FileBody(new File(path));
StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);
HttpEntity reqEntity = MultipartEntityBuilder.create()
.addPart("bin", bin)
.addPart("comment", comment)
.build();
httppost.setEntity(reqEntity);
CloseableHttpResponse response = httpclient.execute(httppost);
try {
HttpEntity resEntity = response.getEntity();
EntityUtils.consume(resEntity);
} finally {
response.close();
}
} finally {
httpclient.close();
}
}
}
 测试结果,如图所示:
  我们程序的逻辑是每请求1000次,打印一次;
  上面的结果翻译的结果就是:
  1----请求1000次,耗费时间为3727毫秒;
  1----请求2000次,耗费时间为6253毫秒;
  1----请求3000次,耗费时间为8713毫秒;
  1----请求4000次,耗费时间为11028毫秒;
  1----请求5000次,耗费时间为13340毫秒;
  …
  依据上面的结果,我们可以做个预估:每秒可以承受的4000次请求;也就是说我们可以大大预估一天有3千万次请求数,这个程序都是可以应付对的;
  但是上面的结论并没说明文件,考虑到并发用户的情况,好!那我们分1个并发,10个并发,100个并发,1000个并发,(我的并发是以线程来区分级别,估计大多数测试工具也是以这样的一种方式去区分,备注:线程并非同一时刻,据本人了解,线程的区分度大概纳秒级别的,还是在同一个进程里面去处理;而进程是可以利用上多核CPU的,举例:4个核的CPU,开4个进程是可以时刻并行的运行,也就是说这4个进程是同一时刻在跑。)
  10线程并发:
  也就是说10个并非,每秒执行9千+;
  100个线程并非:
  也就是说100并非,每秒执行1.5万次;
  1000个并非:
  已经挂掉了,也就是说这个小的后端程序能够承受的并非级别是100~1000之间(一台主机的情况,如果是集群的话,100万台服务器的话,相当于并发在1亿~10亿之间,如果按照业界传闻facebook的几十万台,Google级百万台,在还没考虑主机CPU、内存的这个测试结果是非常可观,目前主机是双核2G内存的主机);
  测试方法就是:java -jar errlogClient.jar path url n c
  各个参数的标识:path = 目标文件路径 ; url = 请求的地址 ; n = 线程总数 ; c = 每个线程调用请求的次数(备注目前上面的程序我是做循环跑的,所以暂时没用上,大家觉得如果需要用上的话可以改改上面的程序)
  这个工具如果大家觉得还凑合用的话就尽管拿去用吧~

posted @ 2014-07-23 09:22 顺其自然EVO 阅读(330) | 评论 (0)编辑 收藏

linux打包压缩命令汇总

     摘要: tar命令 [root@linux ~]# tar [-cxtzjvfpPN] 文件与目录 ....参数:-c :建立一个压缩文件的参数指令(create 的意思);-x :解开一个压缩文件的参数指令!-t :查看 tarfile 里面的文件!特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!因为不可能同时压缩与解压缩。-z :是否同时具有 gzip 的属性?亦即是否需...  阅读全文

posted @ 2014-07-22 10:08 顺其自然EVO 阅读(163) | 评论 (0)编辑 收藏

深入理解Linux操作系统守护进程的意义

     摘要: Linux服务器在启动时需要启动很多系统服务,它们向本地和网络用户提供了Linux的系统功能接口,直接面向应用程序和用户。提供这些服务的程序是由运行在后台的守护进程(daemons)来执行的。守护进程是生存期长的一种进程。它们独立于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。他们常常在系统引导装入时启动,在系统关闭时终止。linux系统有很多守护进程,大多数服务器都是用守护进程实现的...  阅读全文

posted @ 2014-07-22 09:30 顺其自然EVO 阅读(187) | 评论 (0)编辑 收藏

NoSql数据库初探-mongoDB环境搭建

NoSQL数据库一改关系型数据库的缺点,更容易的集成、分布式、无模式、故障恢复等特点,正在一步步餐食关系型数据库的市场,作为一个与时俱进的码农了解一下新技术是必须的,尤其是在读了《NoSql精粹》之后,更是想体验一下NoSql数据库的威力。
  MongoDB是一种文档数据库,也就是说对于领域模型中的每一个聚合来讲,都会作为一个文档来存储。
  MongoDB有如下优点:
  面向文档存储、全索引支持、同步机制和高访问性、自动分片、查询、灵活的聚集和数据处理、映射化简、文件存储。
  第一步:安装
  从版本2.2开始,mongoDB就不支持XP操作系统了,蛋疼,现在我就在用XP,看来只能用2.2之前的版本了,
  可用的版本只有一个2.0.9,我已经共享到百度网盘了,下载地址:http://pan.baidu.com/s/1i3GEs1v,如果下载地址失效了,请去官网下载。
  第二步:设置数据库环境并启动数据库
  将压缩版解压之后放到任意一个硬盘上,比如我就放到了E:\mongodb-win32-i386-2.0.9
  先创建一个存放文档文件的文件夹,E:\mongodb-win32-i386-2.0.9\data此文件夹是用来存放数据文档的
  创建完成之后,将此文件夹配置到mongoDB,让mongoDB将数据存放到此文件夹。
  配置并启动数据库:
  运行命令行:E:\mongodb-win32-i386-2.0.9\bin\mongod.exe --dbpath E:\mongodb-win32-i386-2.0.9\data
  (如果没有指定,mongoDB启动时默认在路径C:\data下存放数据文档)
  第三步:
  数据库启动之后,我们就可以连接数据库进行访问并存储数据了
  另起一个命令窗口并运行:E:\mongodb-win32-i386-2.0.9\bin\mongo.exe --dbpath E:\mongodb-win32-i386-2.0.9\data
  后面的参数是要连接到的数据目录
  默认情况下mongoDB会选中一个名叫test的数据库,如果不知道当前所处的数据库,可以运行db命令来查看
  查看所有的数据库:
  show dbs
  切换数据库:
  use mydb
  如果此时切换的数据库不存在,没关系,只要不向该数据库存放数据,mongoDB是不会在硬盘上创建该数据库的。
  是该存放数据的时候了,先说一下mongoDB中的一些概念。
  mongoDB中有db、collection、document,db就对应关系数据库中的数据库,而collection则对应了关系型数据库中的表,而document就对应了关系型数据库表中的一行数据。mongoDB中的文档就像一个json文件一样,我们可以将一个javascript中的对象字面量创建为一个document,如通过如下方式定义了两个对象变量:
  j = { name : "mongo" }
  k = { x : 3 }
  将j和k这两个文档存入名为“testData”的collection中
  1
  2
  db.testData.insert( j )
  db.testData.insert( k )
  前面已经说过了,db为当前所处的数据库对象,而testData是一个collection,此时还没有对应的collection,当insert执行完毕之后,就创建了collection对象
  我们可以通过
  show collections
  命令来查看当前数据库中所有的collection
  此时会返回testData和 system.indexes, system.indexes是mongoDB自己提供的collection,不用管它
  我们可以通过如下语句查询testData中的所有的数据
  db.testData.find()

此时的find方法会返回一个游标对象
  因为此时并没有一个变量接收该游标对象,所以会默认至多打印出20条数据(当然只会打印刚刚的那两条数据,因为我们的testData中只有这两条)
  { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
  { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
  _id属性是mongoDB自动生成的,因为每个文档都要有一个“主键”(跟关系型数据库中主键很像),而此时我们并没有提供_id。
  我们来试着添加更多的数据:
  在命令行中输入:
  for (var i = 1; i <= 25; i++) db.testData.insert( { x : i } )
  一个for循环,循环插入了25条数据
  我们再执行一下
  db.testData.find()
  结果输出

{ "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
{ "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "x" : 1 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "x" : 2 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "x" : 3 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990be9"), "x" : 4 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "x" : 5 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990beb"), "x" : 6 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bec"), "x" : 7 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bed"), "x" : 8 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bee"), "x" : 9 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bef"), "x" : 10 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf0"), "x" : 11 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf1"), "x" : 12 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf2"), "x" : 13 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf3"), "x" : 14 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf4"), "x" : 15 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf5"), "x" : 16 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf6"), "x" : 17 }
{ "_id" : ObjectId("51a7dc7b2cacf40b79990bf7"), "x" : 18 }
has more

  只输出了20条数据
  后面还有has more提示后面还有数据
  再在命令行中输入it会输出下一批20条数据
  如何才能将数据全部输出呢?
  此时我们用一个变量来接收游标:
  var c = db.testData.find()
  c就是游标对象
  此时我们通过for循环将全部数据输出:
  while ( c.hasNext() ) printjson( c.next() )
  printjson方法将文档以json的格式输出
  游标对象的hasNext方法用来判断是否还有下一个文档,而next方法用来获取下一个文档。
  如果我们只想获取第5个文档,该怎么办呢?
  当然可以在遍历游标的时候对遍历过的文档计数,并将第5个文档输出即可,但是这种方式确实是有点啰嗦了。
  我们此时可以在游标对象上直接添加一个下标即可,如:
  printjson( c [ 4 ] )
  此时输出了第5个文档
  { "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "x" : 5 }
  但是此时请注意:
  c [ 4 ]方法会将所有该collection下的文档读取进内存,这相当于在游标上执行了cursor.toArray() 方法,
  此方法将所有的文档加载到了内存中,然后再在返回的数组中查找索引值是4的文档,所以游标下标方法应慎用啊
  如果我们想查询a是18的那个document该怎么办呢?
  此时我们还可以借助find方法,但是此时要给find方法提供一个模板文档
  一个模板文档详细描述了查询策略,如:db.testData.find( { x : 18 } )
  此时的{x:18}就是一个模板文档,是指查询文档时只保留x为18的文档。
  查询结果如下:
  { "_id" : ObjectId("51a7dc7b2cacf40b79990bf7"), "x" : 18 }
  不要忘了,find方法返回一个游标对象,只不过此时的查询只有一个文档符合条件。
  如果只想返回一个文档,而不是游标对象,可以使用findOne方法,findOne方法返回一个文档对象,不管符合条件的文档有多少个,它只返回第一个。
  如果想对返回的文档数目进行限制,可以在游标上调用limit方法,如下:
  db.testData.find().limit(3)
  只会返回前3个文档
  结果如下:
  { "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "x" : 1 }
  { "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "x" : 2 }
  { "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "x" : 3 }

posted @ 2014-07-22 09:29 顺其自然EVO 阅读(202) | 评论 (0)编辑 收藏

Java中的HashMap浅析

 在Java的集合框架中,HashSet,HashMap是用的比较多的一种,顺序结构的ArrayList、LinkedList这种也比较多,而像那几个线程同步的容器就用的比较少,像Vector和HashTable,因为这两个线程同步的容器已经不被JDK推荐使用了,这是个比较老式的线程安全的容器,JDK比较推荐的是采用Collections里面的关于线程同步的方法。
    问题来源:
    1.为什么要有HashMap?
    《Thinking In Java》里面有一个自己采用二维数组实现的保存key-value的demo,书上也说到性能问题,因为从数据结构的顺序结构的观点来看,常规的线性存储,你弱需要找到其中的某个元素,就需要遍历这个链表或者数组,而遍历的同时需要让链表中的每一个元素都和目标元素做比较,相等才返回,Java里面用equals或者==。这对性能是毁灭性的伤害。
    2.HashMap的优势是什么?
    Hash算法就是根据某个算法将一系列目标对象转换成地址,当要获取某个元素的时候,只需要将目标对象做相应的运算获得地址,直接获取。
    3.Java中的Hash?
    事实上Java的数据无非就三种,基本类型,引用类型(类似C里面的指针类型)和数组,有些地方说是2种类型,只有引用类型和数组。通过这三种数据类型可以构建出任何数据结构。在Java中,ArrayList这种底层就是用Objec数组来构建的,而HashMap也是用数组来构建,只不过数据数组的数据类型是一个叫做Entry的内部类来保存key、value、hash(不是hashCode)和next(也就是链表的下一个元素)。其实HashSet也是HashMap,只不过比较特殊,没有使用Entry的value而只用了key而已。看看HashSet的构造方法:
    public HashSet() {
    map = new HashMap<E,Object>();
    }
    所以从这个意义上来讲就没必要讨论HashSet了,他只不过是特殊的HashMap而已。
    HashMap详解:
    基调:由于通过hash算法产生的逻辑地址可能导致冲突,所以对于一个长度为length的数组,里面存放小于length个数据元素的时候就有可能出现冲突的现象,因为比如说要在长度为16的数组中存放字符串(也就是一个空的HashMap默认的长度),每个字符串通过调用自身的hashCode()方法会得到该字符串的hashCode,然后通过HashMap的这两个方法会算出在数组中的位置,也就是下面的 i。
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    任意字符串的hashCode通过上面2个方法都会得到一个i,这个i就是在数组中的位置,这里比较巧妙的设计就是indexFor(hash,table.length)这个方法:
    static int indexFor(int h, int length) {
    return h & (length-1);
    }
    这个方法里面的任意h与(length-1)做位运算之后得到的值始终都是在length之内的,也就是在数组table之内,因为拿任意一个数来和另一个数来做与运算,结果肯定是小于等于较小的哪一个数,我以前第一次看到这就比较震惊,为什么那些人能想出这么巧妙的计算在table中的位置的方法。与此同时,既然字符串调用hashCode()会得到一个值,那么就会出现不相同的字符串调用hashCode方法之后得到的值是一样的,这种可能性是存在的,而且几乎肯定是存在的。这时候就需要在数组的某个位置增加一个链表结构,用户存储相同的hashCode的字符串,而这个时候HashMap的size同样也会自增1,尽管这2个字符串只有一个存在于数组中。HashMap中的size变量有两个作用,第一是通过调用size()方法来返回map的长度,
    public int size() {
    return size;
    }
    第二个作用相当重要,就是解决hash算法的核心力量,解决冲突。在HashMap的构造方法中可以看出,hashmap的长度和底层数组table都是capacity,但是还有一个变量叫做threshold,极限值,阈值的意思,默认情况的构造方法:
    public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    table = new Entry[DEFAULT_INITIAL_CAPACITY];
    init();
    }
这个阈值就是数组长度和加载因子的乘积,这东西有什么用呢,假设都按照默认情况来看,默认构造方法构造出来的hashmap长度为16,底层数组长度也为16,而阈值
    threshold长度为12,因为默认加载因子是0.75。也就是说当箱map中存放12个元素是,map的结构没什么变化,但是当存储第13个的时候,table就需要扩容了,扩大为原来的2倍。这时候是什么结局呢,如果加载因子是1,那么map中存放16个的时候他是不会扩容的,table.length = 16,而为0.75的时候存放16个数据的时候table.length = 32。那么同样是存放16个数据,分别在长度为16的数组和32的数组中存放,出现冲突的几率一般来说16的数组要大一些,那为什么会大一些呢,因为某个数据存放进入数组的位置是根据
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    这两个方法算出来的,其中就包括table.length,换句话说,位置i跟hash和table.length是相关的,也就是说位置i与table.length是联动的,换个角度,存放的16个数据假设是固定的,而得出hashCode的算法也是固定的,那么位置i就只跟length的大小有关联了,一般来说length越大,数据的冲突几率就低一些,在map.getValue(key)的时候需要在链表中比较的次数就少一些,性能就高一些。这就是Java中hashmap的性能因素,一般来说加载因子factor大,同样个数的数据所占用空间就越小,table.length就越小,冲突几率就越大,反之空间利用率低,性能高,类比一下,比如你地上放了10个碗,你手里面握了10颗大米,你撒下去,前提是必须10颗米都要撒进碗里,你是不是会发现有些碗里面装了两颗三颗,而有些碗是空的,接下来,你在地上摆20个碗,还是撒10颗米下去,依然是所有的米都要进碗,依然还是会出现有些晚是空的,有些是一颗两颗三颗这种现象,但是很明显一般来讲20个碗的时候每个碗里面装不止一颗的情况要比10个碗的情况要少,当然也不一定完全是这样,但是一般来说是这样,这就是hash算法,如果设计的好的情况下我们希望每个碗里面都最多放一颗进去,但是这种情况比较少见,但不管怎么说,按照普遍情况来看,20个碗的装多颗的情况是比10个碗装多颗的情况要少一点。从数据结构的角度来说叫做用空间换时间的策略,以空间换时间何止hash算法,双向链表也是用空间换时间的策略。至于说为什么默认是0.75,我估计这个是前辈们和科学家们总结出来的一个这种的办法,空间利用率比较不错的同时性能比较令人接受吧。
    顺便说一下啊,当我们不断的往一个hashmap里面添加数据的时候,如果超过某个阈值,他就会扩容,扩容的同时会让之前的所有元素重新生成地址,并且把原来的数组里面的数据迁移到新的数组中(新的数组容量是原来的两倍长度)。顺便说下,这个数据迁移其实对性能损耗还是相当大的,毕竟你是要复制数组,同时要重新构建每个元素的在table中的位置,因此我们可以在使用hashMap之前大概的估算一下这个hashMap里面大概会存多少个元素,这样就可以在new hashmap的时候就给定他的容量,这样数据迁移的次数相对就少一些,性能就更好一点。
    接下来从JDK的源码来看看HashMap。
    1.构造出一个空的HashMap。默认长度16,底层Entry数组也是16的默认长度。默认加载因子default_factor为0.75。阈值16*0.75=12。key和value都存在与Entry这个类型里面。
    public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
    table = new Entry[DEFAULT_INITIAL_CAPACITY];
    init();
    }
    2.调用put方法。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

    首先是判断key是否为空,如果为空,那么调用下面这个方法,这个方法说明,HashMap的null的key始终是存放在table的table[0]位置的,不管table[0]位置有没有冲突都是这样。
private V putForNullKey(V value) {
for (Entry<K,V> e = table[0]; e != null; e = e.next) {
if (e.key == null) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(0, null, value, 0);
return null;
}

    如果不为空,那么继续,这里,如果算出来的位置i出已经有元素了,说明冲突了,那么遍历冲突链表,如果发现key相等,那么直接用新的value替换掉就的value并且返回旧的value。这里只判断相等的情况而不判断不相等的情况,也就是这里不做添加操作。
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}

    接下来,上面的步骤说明,新添加的数据在位置i处不是key相等的情况,就真正的添加数据了。调用addEntry(hash, key, value, i)方法。
    void addEntry(int hash, K key, V value, int bucketIndex) {
    Entry<K,V> e = table[bucketIndex];
    table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
    if (size++ >= threshold)
    resize(2 * table.length);
    }
    此时把新的添加进table[i]位置,而原来的数据(可能是null也可能是一个链表)的引用直接存放进新的数据的next中。形成新的链表。
    接下来就是调用map的get(key)方法了。这个过程和put方法是逆向的。
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}

    首先判断key == null, 如过为true,那么调用getForNullKey()方法。遍历table[0]出的链表,因为空key是存在table[0]处的。前面说到。
    private V getForNullKey() {
    for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    if (e.key == null)
    return e.value;
    }
    return null;
    }
    如果key == null 为false,那么上面get方法的下半部分,通过hashCode算出hash,通过hash和table.length算出位置i,遍历table[i]处的链表,ken相等,取出数据。
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;

    这里还有一个Java里面的规定,就是2个对象的equals相等,那么hashCode也必须相等。但是hashCode相等equals不一定相等。这是hashmap存在于Java里面的依据,同时这就是为什么会有冲突的原因了,两个不一样的对象计算出来的hashCode相等的原因。如果2个对象equals相等,但是hashcode不想等,那就说明这2个元素都能存进hashmap,但是很明显hashmap里面的key是唯一的,直接就推翻了hashmap。
    写得比较粗糙,HashMap里面的很多细节都没写,主要是因为一来我们只需要用HashMap就行了,二来是细节源码里面都有,看一下就知道了。

posted @ 2014-07-22 09:24 顺其自然EVO 阅读(622) | 评论 (0)编辑 收藏

群体测试活动指导总结

信息技术世界正从由企业驱动向由客户驱动转变,客户需要更的灵活性以便他们可以通过各种环境和体系去操作其设备。这就向软件设计师和他们的质量保证团队提出了挑战。高质的设计和功能是建立客户忠诚度的先决条件,。群体测试让实际用户在真实条件下测试软件。这就使公司能够快速廉价地搜集真实的看法,反馈和缺陷,从而显著改进质量和设计,并通过客户和最终用户提高软件采用率。使用群体来测试软件改善了外包或自动化等其他常见选择的质量,灵活,速度和成本水平。如今,精心设计和高质量的软件是建立客户忠诚度的先决条件。为了确保软件满足客户对精准设计,实用性和性能的期望,有必要进行广泛的测试。软件要在各种不能提前预测的设备和使用场景上执行。内部测试的测试资源有限,不能满足如此广泛的测试覆盖要求。众包软件测试让真实用户在真实条件下测试软件,这样企业就能快速廉价地搜集真实的看法,反馈和缺陷,从而显著改善质量。
  1.引言
  过去几年,众包模式已从不起眼、被孤立的自定义行为演变成了成功案例,如维基百科和亚马逊土耳其机器人。在信息技术领域,众包软件测试越来越多地被关注及采用,尤其是创业公司和小公司。但是,大企业的采纳过程相当缓慢,主要是因为缺乏出版商业文献。为提高大型企业对群体测试的采纳率,我们需要讨论一些关键问题,如制造或购买的决定,建立一个内部测试社区或与外部机构合作,应用程序适应性,管理和测试员质量,并通过提供一些成功的群体测试活动指导作总结。
  2.今天的IT环境
  近年来,信息技术(IT )已认识到它的战略重要性,许多企业已对ERP,CRM和其他业务的工具进行了大量潜在投资,这表明了企业IT的关键性质。这些公司也有面向消费者的要素,如网站和移动应用程序,这些要素不仅是精心设计的,而且还提供无中断的功能。预测此类系统的用户并先验他们的喜好几乎是不可能的。众包软件测试可以通过确保该软件无缺陷帮助大幅提高消费者接受软件模块的概率。随着云计算, BYOD等不断增长的趋势,IT服务被交付到多个渠道并被IT系统配置不同的各利益相关者使用。真正强大的软件测试很费时,而且几乎无法保证功能,位置和平台的每一个可能的排列组合能如期工作。例如,如果一个Web应用程序无法在某个特定浏览器上运行,或一个特定的软件工具无法使用一个重要功能,那么业务可能会中断。通过群体测试,企业可以有效地降低内部软件测试团队在内部测试阶段错过关键要素的可能性。根据Paul Herzlich,一名Ovum(一家独立的IT业研究机构)的软件测试分析师的看法,“如果你正在测试一个各种陌生人都要使用的软件,干嘛不让一大帮陌生人来测试它呢。”于是,群体测试给或许会成为一个棘手难题的测试提供了一个简单,简练,有成本效益的解决方案



  图2.众包的各地利益(从谷歌走向看)



  3.探索和企业群体测试
  目前,大部分重点是探索性群体测试服务,测试人员根据通用准则和测试用例分析软件的问题,bugs,或缺陷。有了“不受约束的”探索性测试,结果不能定量预测,因为要提前限定范围,地区和可能存在的缺陷数量很困难。测试人员通常可以发现在最明显地方的问题,但一些高水平测试人员可能会发现软件层下的缺陷。探索性测试最适合用于测试有大量用户但不重要的应用程序,以确保不同配置下的一系列问题的再现性或在应用程序上模拟一个典型工作内容。企业群体测试集成在软件测试过程中更加严谨,包含更多结构,同时保留了探索性测试的精神和敏捷性。因此,企业群体测试包括正规和非正规的软件测试方法的最佳实践和概念。企业众包软件测试的专业程度更高。在这种方法中,测试人员均须经过严格审核,并根据全面的选择标准部署。软件测试过程包括明确规定的范围,并由广泛的特定指导方针指导以满足项目需求。团队已明确规定了角色和职责,一个联系客户组织,正式报告和报告结构,广泛文档和项目跟踪等的单独社区点。此外,企业群体测试包括建在现有软件测试方法上的正式程序,例如Agile,SCRUM等。这样对齐的结果是,客户组织的内部开发和外部软件测试周期间轻松同步了。这就使客户端可以减少其项目管理的开销并最大化两队的利益。


  图3


  4.什么样的应用程序适合用众包测试?
  众包测试方法最适合以用户为中心的应用程序。它常常,通过在公测阶段推出廉价或免费产品版本,被用于移动应用和游戏开发项目中。大型企业可以通过模拟一个庞大的用户群去了解使用模式并根据反馈进行完善同时确保其应用程序在各种设备,操作系统,浏览器和语言版本中流畅运行而获益。换句话说——有高缺陷暴露因素,即关键性作为即时客户发布后暴露的措施的应用程序适合用群体测试。例如,微软发布Office 2010产品系列的测试版本,被900万人下载和测试并提供了2百万条宝贵意见和见解,从而使产品获得确实的改进。
  5.它是如何运作的呢?
  大多数众包测试公司为测试周期提供平台和项目管理框架,包括管理政府和法律结构。群体测试公司还分配一个负责测试过程的合适的项目经理。众包软件测试服务的消费者方面,客户指定他们希望执行的测试类型和测试系列,测试员的技能和个人信息,软件必须在上面进行测试的设备的类型和配置等。客户公司也可以咨询群体测试公司确保测试充分。供应商方面,测试人员完成一个配置文件,表明他们的背景和资历,他们有权访问的设备和平台,以及其他相关细节。测试人员有时需要参加评估或试验项目作为他们成为社区成员的先决条件。在项目启动之前,会给测试人员提供详细的测试计划,示例场景,工具,脚本和说明。在执行过程中,测试人员记录下他们的观察,并根据观察报告的数量和质量被评分,这与他们的薪酬和激励结构直接挂钩。社区结合协作和竞争,成员合作找出解决方案说明问题。论坛促进知识管理,网络以及bugs或相关问题的讨论;评分系统可以识别所做的出色工作,这有助于参与者获得信誉并完善自己的职业生涯。群体测试应被视作产品发布前的额外补充测试而不是一个独立的活动及一个组织内部测试团队的替代品。这对在生产前发现误差UI和配置缺陷很有效。


  6.现场,外包和测试群体
  现场测试是指为了软件测试目的部署一个内部团队的一贯做法。这种方法在可扩展性方面有局限,且对再现现实使用情况无效。外包软件测试中,外部服务供应商基于每个项目或协议提供软件测试。外包软件测试具有明显的成本优势——高技能资源只占一小部分成本——通过劳动套利。在群体中测试中,测试人员自愿测试软件,内在驱动其去发现软件缺陷,在社区内自己的一席之位,获得同行的认可,等等,尽管没有发现缺陷他们就没有薪酬。这种自发组织的特征,共享社区目标,内在动机是群体测试成功的强大力量。
  7.选择什么呢?
  现场团队,因为接近客户,可以通过关注需要立即关注的技术和商业挑战创造价值。在一个外包测试项目中,测试团队(S)可以受外包公司控制也可以不受之控制。受控模式中,测试团队是公司的一部分,它们把软件测试作为一项持续性活动(测试团队可以从中通过对最常见的内部应用程序的更深理解而获取经验和效率水平)进行。不受控团队是公司外部的,它们与一些客户合作一些项目。从这些约定来看,不受控团队汇集了多个地方,领域,功能,行业,技术方面的经验和专业知识。客户公司可以在需要“创造性思维”和特殊测试工作的项目中利用这种多样性。群体测试团队的焦点,重心,内在动力和可扩展性,通过在上线前发现问题提供巨大的价值。群体知识在测试员基地中扩散,但集体测试的知识基地大于任何公司内部基地。考虑到现代系统的复杂性,最佳的测试组织按正确比例应包括现场,外包和众包测试团队。按正确比例汇集是经验和实验一个关键因素。
  8.建立一个社区还是建立合作伙伴关系?
  虽然一些公司,如Netflix和亚马逊,已经在内部建立了他们自己的群体功能,但这不是大多数公司能够自己实现的或有战略性商业意义的活动。群体测试是一项复杂的活动,需要深厚的技术,功能和业务知识。所以,除非要完成的工作是高度战略性或机密的业务,公司最好立即寻求提供所有必要成分的群体测试公司来部署群体。这些成分包括有经验的测试人员,设备,可配置架构,参与机制,基本规则,参与方法,法律结构,支持机制等。
  9.安全和管理
  往往,客户保密信息在测试期间面向群体。群体测试企业已经意识到了安全性和保密性的需求;因此,他们有各种过滤器,管理机制,模糊处理工具,数据管理框架等,以向他们的客户确保他们的数据和信息极度保密处理。对于对安全性要求高的项目,拥有长期信誉和专业声誉的白帽测试工程师的预先筛选名单会被提议,且通常会被接受。测试数据管理通过混淆敏感信息或创建“只测试”数据以确保安全。这有助于减少大规模测试中潜在安全漏洞的影响。测试人员加入社区时还必须签署一份常规保密协议(NDA),禁止他们线上线下在社交网络、个人博客及其他秘密测试平台外的地方谈论他们的客户,产品等。客户也可以自由地从池中选择自己的测试人员并在看顾客项目之前提供每个被选测试人员必须签署的自定义NDAs。此外,标准的沟通渠道,准入限制等在测试工作中帮助确保数据并保密,这就使得群体测试项目生命周期各阶段可以无缝过渡。
  10.确保测试质量
  为了保证测试员的质量,正式和非正式的测试,可以根据测试员的经验,可用材料和所掌握概念定期由单个测试员管理。测试人员和项目经理不断监控以确保质量和完整性。经过不断的筛选,没有正式培训和显著专业经验的申请人被淘汰。越来越多地,群体测试公司也赞助有经验的测试人员去考专业证书,所以他们的地位和责任随着他们的贡献而增长。为了避免测试人员之间的潜在利益冲突,实行基于绩效的薪酬机制以确保测试人员的报酬与他们的参与度和对软件质量改进的贡献水平一致。发现大量不重要缺陷的测试员的报酬低于发现少量极具影响力的缺陷的测试员。这些机制也有利于防止社区内的任何口水之争,阴谋诡计等,并提高测试者对社区的关注,所有权,忠诚度和隶属关系,从而创造一个和谐的,彼此尊重的工作环境。
  11.选择一家群体测试公司
  群体测试过程的各个阶段中,选择合适的测试公司无疑是最重要的。客户公司在选择一个群体测试平台之前要进行充分调查,广泛的项目评估,测试公司的能力和规模等都是必须的。一般情况下,选择一个成熟的,经验丰富的群体测试平台,可以使业务活动更加容易,因为这样在运行阶段通常就不怎么需要维护及管理,因为测试公司已经根据过去与其他客户合作的经验解决了许多相关问题。因此,至少按下列标准评估群体测试平台以确保平台至少包含所需的最少功能和安全非常重要:
  一.确定群体测试的经验,交付能力,技能多样性,全球拓展情况以适应企业客户不断变化的需求很重要。
  二.与企业和中型公司合作的有机增长及经验表明了可靠性。让小型的众包测试平台提供移动应用程序和网站测试服务相当简单,但很少有企业成熟到可以测试企业应用程序并提供总包测试服务。
  三.如果客户公司一心进行长期项目而不想担心服务提供商退出的话,一段时间内的财政稳定就尤为重要。
  四. 许多群体测试平台仅有客户端和测试人员之间牵线搭桥服务,而不提供管理服务。这些平台不保证软件测试人员的数量,各个测试人员的测试工作量,测试人员的质量或测试结果,也没有任何可靠的结果。最好避免这样的平台。
  五.要了解它们的服务范围和所提供的SLA,必须刻苦温习条款。
  六.标准文档的采购级层应该用于为每一个重要的群体测试项目评估平台运营商。该文件应处理各种元素,如:
  1.价格结构
  2.质量,安全,保密性
  3.专业的服务
  4.功能和流程
  5.交付方法
  6.服务基础设施
  7.补偿结构
  8.便利性和可扩展性
  9.平台和工具的功能和质量
  10.风险管理结构
总结
  已经讨论过群体测试的各种元素,可以很容易地推断,大企业可以通过既定的和有经验的群体测试公司合作,以节省大量成本并获得可扩展性。群体测试工具,流程,框架和方法已经成熟到如此高的程度,那么群体测试就可以很容易地融入组织的常规开发周期。群体测试通过一个更大团队中的多种软件测试活动减少人为错误的可能性。通过把应用程序提交到现实中,可以追踪到能重新设计或改进的实际性能数据和执行路径,从而进一步改进产品质量。除了这些直接的好处,大公司还可以体验更快的产品上市时间,把资源都放到核心业务上,获得大量人才,增加灵活性等。开始很容易,而那些敢于冒险尝试的组织肯定可以获得一些短期和长期的好处。

  Dieter Speidel是PASS集团的创始人和CEO,一名重要的瑞士软件和系统测试服务的供应商。 PASS集团是passbrains.com的所有者和passbrains之家,一个在苏黎世,柏林,波士顿,贝尔格莱德,班加罗尔和孟买都设有办事处的按需群体测试服务的全球平台。作为一名在IT外包,软件开发和测试业活跃了30多年的企业家,Dieter Speidel对全球交付模式,包括近/离岸外包和众包方面有深入的专业知识。2011年以来,他一直专注于从众包模式的应用深入到IT相关的服务,并开发passbrains平台和社区的群体测试和知识服务。
  Mayank Mittal是应用程序测试行业的一名战略性业务领导。十多年的职业生涯,他已建立了大规模的管理测试中心并在与领先机构,如Oracle、CSC、Cognizant合作时进行了QA组织变革,为全球许多财富100强客户提供了测试解决方案。Mayank在PASS集团股份公司担任公司战略和业务发展主管。
  Mithun Sridharan是Passbrains的一名业务发展经理,Passbrains总部设在德国Eschborn 。他在业务发展,市场营销,全球交付和咨询方面有十多年国际经验。他是工商管理硕士(MBA)和科学硕士(M.Sc)。他是一名项目管理专业人员(PMP)和国际信息系统审计师(CISA) 。他还担任德国外包协会的通讯主席。

posted @ 2014-07-22 09:21 顺其自然EVO 阅读(151) | 评论 (0)编辑 收藏

在QTP中申明XPath

 Example 1:
  <body>
  <h4>John Smith<input type=checkbox name="select" /></h4>
  <body>
  <h4>Anne Anderson<input type="checkbox" name="select" checked=true /></h4>
  In QTP:
  'Selecting John Smith
  Browser("XPath").WebElement("xpath:=//h4[1]").Click
  'Selecting Anne Anderson
  Browser("XPath").WebElement("xpath:==/h4[contains(text(), 'Anne')]").Click)
  Example 2:
  XPath:
  1. (//tr[@class='row2']/td[1])[2]
  2. (//td[contains(text(),'Address')])[2]
  In QTP:
  1. Browser("XPath").WebElement("xpath:=(//tr[@class='row2']/td[1])[2]").Click
  2. Browser("XPath").WebElement("xpath:=(//td[contains(text(),'Address')])[2]").Click
  Example 3:
  <table id='table1'>
  <tr class='row1' id=BPT>
  <td>View ID</td>
  <td><input type='button' value='Button 1' class='btn_blue' id='btnfirst'></td>
  </tr>
  In QTP:
  'Selecting Button 1
  Browser("XPath").WebButton("xpath:=//td/input[@id='btnfirst']").Click
  'Select Button 1
  Browser("XPath").WebButton("xpath:=(//table[@id='table1']/*/*)[1]/*[2]/input").Click

posted @ 2014-07-22 09:20 顺其自然EVO 阅读(426) | 评论 (0)编辑 收藏

软件测试员——面试,你准备好了么?

 最近有机会做一些面试工作,主要负责面试软件测试人员招聘的技术面试。
  之前一直是应聘者的角色,经历了不少次的面试之后,多少也积累一点面试的经验,现在发生了角色转变。初次的面试就碰到个工作年限比我长的,也没有时间仔细了解对方的简历,再加上应聘者比较“强势”。面试情况是比较糟糕的。
  有同学会说,唉!不就失去了一个应聘者嘛。多面几个就好了!这不单单是失去应聘者,面试者对面试官的印象更重要。面试官的能力与表现对于初次面试者来说往往代表的是公司的,更具体点是测试团队的能力。
  如果面试官都很“水”,这个水两方面,一是面试不够从容,思路不清晰。二是技术能力水,问半天问不到关键点上。那么身为面试者,对这家公司的印象会打折很多,就算能开得起面试者的期望薪资,面试者还要考虑在你这儿能不能学到什么,工作是否有挑战,是否有发展空间。
  所以,面试官的能力与表现对面试是否成功同样重要,毕竟就面试过程而言是一个双向选择的过程嘛。
  下面讨论测试人员应该具备的技能。
  在这个讨论的过程中,充满了我个人的偏见与喜好。不喜误喷!
  上面是我所画的一个体系图,这上面的技能相对比较通用,当然特殊情况下对测试人员的技能要求会有特别要求。
  软件测试基本知识:
  这一块其实没什么好讨论的,如果你有半年到一年的工作经验的话,对这一块一定有比较清晰的认识,当然,在实际的工作中不需要你对每一种测试方法去寻根求源,知道这些方法的含义与应用场景即可。
  编写各种测试文档,对于初学者来说稍有难度。但终究还是谈不上什么技术含量的事情,如果对业务和流程足够熟悉,文档用例自然就会写了。
测试辅助技能:
  我发现这两项技能在笔试和面试过程中必考,出现几率超高,但在实际的工作中,有些测试根本碰不到linux ,有些测试不需要去操作数据库。当然,测试嘛,也不能太处于表面了,也需要熟悉熟悉相关测试的表,了解了解系统服务器。
  好在这两项技能的要求都不高,linux 大多考几个常用命令,SQL一般考一下增、删、查、改。
  自动化技术(UI):
  大多同学会在简历必备测试技能里加一个QTP自动化测试工具,当我满怀起到和他聊一聊自动化时,得到的多大回答是这了解和学习过这个工具。这也不能怪测试人员,谁让满大街的招聘要求上都写着“要求熟悉LoadRunner 、QTP等自动化测试工具等。” 其实,他们公司根本就不用。这么多公司都要求,看来还是有必要学一学这个工具的。
  对于我而言,我并不太关心工具用得多熟练?对于web应用来说,更在意的是对前端技术了解多少?因为你要自动化的对象就是前端技术所呈现出来的各种功能。都不了解它,如何定位和操作它呢?
  UI的自动化不单单是QTP一个工具,如果你掌握了一种语言,做自动化的路就宽广了,你一定知道还有个叫selenium(webdriver)的自动化工具,你不一定知道ruby 有个watir框架也可以做自动,也许你不知道python有个splinter框架也可以做自动化。那么你就更不知道python 有个pywinauto框架可以对windows GUI做自动化。你不知道有自动化工具太多太多了。谈到这些就不得不涉及到编程技术了。相比较而言QTP 不需要太多的编程能力。
  对于自动化测试,另一个比较关心的是你对自动化的理解,什么情况下适合做自动化?你的自动化测试用例是怎么写的?什么样的用例适合转成自动化?你是如何来实施的?有什么样的策略来开展自动化工作?你需要自动化在项目中达到一个什么样的预期和效果?只是学学工具,拿个例子练习练习。很难对这些问题有真实的理解。
  性能测试:
  LoadRuner似乎比QTP名气更大,做测试必玩工具。没摸过LR都不好意思说自己是做测试的。性能测试是必须是要借助工具来实现了。不借助工具如何模拟成百上千的并发?
  最大的难点,其它是对系统架构的理解,其实,更多时候并不需要达到架构师水平,甚至不用达到开发的水平,但起码,你要弄清用的什么操作系统,什么数据库,什么开发语言与框架,什么中间件吧!你要知道如何对这些做监控的吧!你要知道叫上开发一块玩吧!
  对于性能测试,另一个我更关心的测试流程,你做性能测试的目的是什么?新系统验证?还是旧系统扩容?需要达到一个什么样的预期?在独立的环境可以开展么?压力在哪儿,脚本为什么要这样录制?你的测试结果真的有知道意义么?或对系统性能做出了合理的评估,或为系统有调优做出指导,或为系统扩容做出了依据。如果前因后果弄不清何必去做呢?
  编程能力:
  编程不局限于语言,大多同学也会在简历的必备技能最下方面写上一条,熟悉C语言或其它某种语言。大多止步于大学C语言水平。工作中没有机会用到。所以,就没机会去进一步提升这方面的能力。这似乎也挺合乎情理的,再说你们招的是测试又不是开发。
  不过,我个人偏执的很看重这一点,至于上面的自动化、性能会不会都无所谓,如果在编程能力上略懂一二,我会大力推荐。懂编程和不懂编程的人看系统的深度不一样,一点不懂的只能看出来这是按钮,那是输入框。 懂编程的就知道你的登录是个<from> ,输入框是个<input> ,你的登录提交是用的post 还是get呢?逻辑层就是获取到输入的用户名密码是查数据库做比较嘛。在测试过程中不管功能实现也好,bug也好,都会看得更透彻,从而更容易挖掘出相关的bug。
  一般懂编程的我都会让其写一个小程序,例如求素数,递归调用,用星号(*)打印一个梯形,如果测试工作写一些脚本之类的来辅助测试更是大大的亮点。不要觉得让你写程序就是“刁难”。平时注意积累这又何难呢?
  对新的工作有什么期待?
  “我希望能接触一些性能测试、自动化测试等,因为之前的工作一直在做功能。”
  大多数测试人员认为提升自已的过程是这样的:
  现在有一个性能需求,然后领导找到你说,小张啊,你来研究研究性能测试吧!我们现在的需要迫切需要对系统做一次性能测试,然后,你回去开始研究性能测试,花一个月终于搞懂了,开始对系统做性能测试。最终完成了任务。
  但实际的情况是这样的:
  现在有一个性能需求,然后领导找到你说,小张啊,你会做性能测试么?答,这个以前没做过,得学习一下。领导说:噢,那这样吧!小王你回去了解一下吧。因为小王虽然也没搞过,但他平时做测试的资历更久,对于新技术更爱钻研。在领导看来,小王能在更短的时间搞定这个问题。如果这个需求迫切或要求更专业,领导会直接招一个专业做性能的。
  所以,结论很明了,机会是给有准备的人的。假如,你在某一技能上面持续积累,总会有发光的时候。
  面试官更多的时候是在找亮点,我只有一个岗位,在面试的十个人当中,有十个人都能把测试流程什么的说得顺溜(虽然我也只招一个懂测试会流程就行了)。有八个人说自己懂QTP、LR等工具,只有两个人真正的有自动化或性能测试经验,只有一个人编程方面还不错。你说面试官会选谁呢?
  亮点也是谈资(谈钱的资本),你和前一个面试者差不多,前一个面试者要5K,你要8K,那我更倾向于前者,如果你有别人没有的亮点,那我更倾向于有亮点者,我更愿意招个牛B的,工资又不是我给你开,最终是否谈拢是你和人事或上级的事儿。
  面试是个综合的过程,假如你思路清晰,思维敏捷。假如你和我一样有写博客的习惯。或者谈谈你最近看的两本技术书。让我看到你是个工作很有热情的人,你是个热爱技术的人。这都是和别人不一样的亮点。闪闪发光。到哪儿都发光。

posted @ 2014-07-22 09:18 顺其自然EVO 阅读(232) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 80 81 82 83 84 85 86 87 88 下一页 Last 
<2025年4月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜