qileilove

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

JavaScript击败Ruby成为Github第一大语言

  Github中参与项目的新用户人数百分比变化情况
  综合图:Github中新项目、issues、参与用户变化情况
  除了上面12种语言外的其他所有语言的变化情况
 Github是一个从Ruby社区诞生出来的项目,最初它是Ruby开发者的大本营。随着开源运动的盛行,Git系统的普及,托管在Github中的开源项目数量越来越多、种类也越来越多样化。
  下图是2008年~2013年,Github中开源项目所使用的编程语言的变化情况,可以看到,Ruby项目的占比最初遥遥领先,在2011年中开始被JavaScriptg赶超,此外,Java语言的份额也在迅速攀升。
  下图反映了Github中新创建的使用某种语言的项目数量的变化情况。可以看到,JavaScript、Java、PHP、Python等项目数量的增长,驱使Ruby项目的占比急剧下降。一些曲线呈现出飞速增长而后平缓的态势,则表明在此期间,该语言社区项目开始大量往Github中迁移。
  C#和Objective-C项目的占比一直较少,这是由于Windows平台和iOS平台相对来说比较封闭,不太鼓励开源项目所致。随着HTML5技术的兴起,CSS项目开始有所起色。
  Github中issues数量百分比变化情况
  Github中参与项目的新用户人数百分比变化情况
  综合图:Github中新项目、issues、参与用户变化情况
  除了上面12种语言外的其他所有语言的变化情况

posted @ 2014-06-30 18:29 顺其自然EVO 阅读(136) | 评论 (0)编辑 收藏

MySql索引优化

在列上创建索引可以优化查询的速度,但缺点是减慢写入数据的速度。
  创建索引的优点:
  第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。
  第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。
  第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。
  第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。
  第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
  索引的缺点:
  第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。
  第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间。
  第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
  在哪些列上建索引:
  在经常需要搜索的列上,可以加快搜索的速度;
  在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
  在经常用在连接的列上,这 些列主要是一些外键,可以加快连接的速度;
  在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
  在经常需要排序的列上创 建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
  在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
  哪些列不应该建索引:
  第一,对于在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
  第二,对于只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
  第三,对于定义为varchar,text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少。
  第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改性能远远大于检索性能时,不应该创建索引。

posted @ 2014-06-30 18:29 顺其自然EVO 阅读(136) | 评论 (0)编辑 收藏

Java多态的内存机制

 学习java也快一年多了,看过很多方面的书,也喜欢在网络上学习优秀的java资料。但是每当自己打开myeclipse时,总是那么的不自信…………,java基础部分的内容自己以及掌握,并能很好运用,加油吧,多实践,多总结,一定会有所突破的。老银每天进步一点点。
  今天就总结一下,自己看过的资料上好的列子。
  1:java面向对象特征:抽象,封装,继承,多态。
  抽象:
  封装:
  继承:
  多态:
  写一个类,来完成以上所包含的抽象,封装,继承内容
class LaoYin extends Thread implements Runnable{
private int  Number=1111111;
private String name ="loayin";
@Override
public void run() {
System.out.println("java学习者");
}
}
java中通过重载,和重写机制来实现多态。
/**
*
* @author YXP 小技巧:当我们想让类中的私有变量让外界访问到:使用SET();GET().
* 简单方法是选中这些变量,右键,source  然后Ganerate Gater and Seter,即可。
*
*/
public class DuoTai {
String  name;
int   age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void cry(){
System.out.println("不知道怎么叫");
}
public  static void main (String[] args){
DuoTai an=new Cat();
an.cry();
DuoTai ni=new Dog();
ni.cry();
}
}
class Cat extends DuoTai{
public void cry(){
System.out.println("喵喵 ");
}
}
class Dog extends DuoTai{
public void cry(){
System.out.println("汪汪叫");
}
}
 答案肯定是我们要的答案,父类调用子类的方法来为自己声明对象。
  但是如果我们改变一下,关于类的成员变量,这里有很大的乐趣………………
  为每一个类声明一个一样的成员变量 count
  基类100,cat是5,dog是50;
  通过多态给基类声明对象,然后通过对象进行调用变量。我们瞧瞧看。
/**
*
* @author YXP 小技巧:当我们想让类中的私有变量让外界访问到:使用SET();GET().
* 简单方法是选中这些变量,右键,source  然后Ganerate Gater and Seter,即可。
*
*/
public class DuoTai {
String  name;
int   age;
int count=100;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void cry(){
System.out.println("不知道怎么叫");
}
public  static void main (String[] args){
DuoTai an=new Cat();
an.cry();
System.out.println(an.count);
DuoTai ni=new Dog();
System.out.println(ni.count);
ni.cry();
}
}
class Cat extends DuoTai{
int count=5;
public void cry(){
System.out.println("喵喵 ");
}
}
class Dog extends DuoTai{
int count=50;
public void cry(){
System.out.println("汪汪叫");
}
}
  运行看看:F11
  喵喵
  100
  100
  汪汪叫
  现在我们就可以很好的明白多态的机制了,但是我有点晕了,对于这个用多态实现的对象,它内存中是如何实现的呢
  当然main栈区呢  有na  ni
  但堆内存中是什么样的内???
  ni(栈内存)
  int count(自身的成员变量) 上下
  cry()子类覆写的cry       (如何现实的不造,原理) 纠结的感觉
  只能是父类引用子类的构造函数,反过来不行。
  多态引用变量会调用子类的方法,但是堆内存上依然存储的是自己的成员变量,只是方法指向了子类的方法吗??。
  如果是指向子类的方法,那么子类必须要实现实例化,所以不成立
  如果子类中有父类不曾有的方法,看看ni还能不能调用,即可知道。
  答案不用说啦,编译不能通过。
  ok,我感觉自己有点明白了一些,多态就是用子类的调用方法,来将子类中重写的父类方法,让父类调用。即父类对象的框架上,将子类的覆写方法覆盖父类的方法,当然父类类上不存在的方法,对象没有内存空间存放子类方法,编译自然就有问题了。总之,多态就是与覆写方法有关,与成员变量无关。

posted @ 2014-06-30 18:28 顺其自然EVO 阅读(164) | 评论 (0)编辑 收藏

Java 8的一些常见用法

 lambda表达式
  语法
  最常用的:
  Runnable runnable = () -> System.out.println("Hello!");
  Thread t = new Thread(runnable);
  t.start();
  t.join();
  你还可以这么写:
  Thread t = new Thread(() -> System.out.println("Hello!"));
  t.start();
  t.join();
  带有参数的呢?
Comparator<String> stringComparator = (s1, s2) -> s1.compareTo(s2);
扩展成一个完整的表达式:
Comparator<String> stringComparator = (String s1, String s2) -> {
System.out.println("Comparing...");
return s1.compareTo(s2);
};
  函数式接口
  Lambda表达式使得你可以更紧凑地表达出单方法类。单一方法类也被称作函数式接口,它可以通过
  @FunctionalInterface来进行注解:
@FunctionalInterface
public interface MyFunctionalInterface<T> {
boolean test(T t);
}
// Usage
MyFunctionalInterface<String> l = s -> s.startsWith("A");
  方法引用
  方法引用就是更紧凑,易懂的Lambda表达式,它适用于那些已经有名字的方法。来看一个简单的例子:
public class Sample {
public static void main(String[] args) {
Runnable runnable = Sample::run;
}
private static void run() {
System.out.println("Hello!");
}
}
  还有一个:
public static void main(String[] args) {
Sample sample = new Sample();
Comparator<String> stringLengthComparator = sample::compareLength;
}
private int compareLength(String s1, String s2) {
return s1.length() - s2.length();
}
  Stream API基础
  stream是一个元素序列,它支持串行及并行的操作。
  遍历列表
  List<String> list = Arrays.asList("one", "two", "three", "four", "five", "six");
  list.stream()
  .forEach(s -> System.out.println(s));
 过滤
Predicate<String> lowerThanOrEqualToFour = s -> s.length() <= 4;
Predicate<String> greaterThanOrEqualToThree = s -> s.length() >= 3;
list.stream()
.filter(lowerThanOrEqualToFour.and(greaterThanOrEqualToThree))
.forEach(s -> System.out.println(s));
  排序
Predicate<String> lowerThanOrEqualToFour = s -> s.length() <= 4;
Predicate<String> greaterThanOrEqualToThree = s -> s.length() >= 3;
Comparator<String> byLastLetter = (s1, s2) -> s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1);
Comparator<String> byLength = (s1, s2) -> s1.length() - s2.length();
list.stream()
.filter(lowerThanOrEqualToFour.and(greaterThanOrEqualToThree))
.sorted(byLastLetter.thenComparing(byLength))
.forEach(s -> System.out.println(s));
  大小限制
Predicate<String> lowerThanOrEqualToFour = s -> s.length() <= 4;
Predicate<String> greaterThanOrEqualToThree = s -> s.length() >= 3;
Comparator<String> byLastLetter = (s1, s2) -> s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1);
Comparator<String> byLength = (s1, s2) -> s1.length() - s2.length();
list.stream()
.filter(lowerThanOrEqualToFour.and(greaterThanOrEqualToThree))
.sorted(byLastLetter.thenComparing(byLength))
.limit(4)
.forEach(s -> System.out.println(s));
  集合转化成列表
Predicate<String> lowerThanOrEqualToFour = s -> s.length() <= 4;
Predicate<String> greaterThanOrEqualToThree = s -> s.length() >= 3;
Comparator<String> byLastLetter = (s1, s2) -> s1.charAt(s1.length() - 1) - s2.charAt(s2.length() - 1);
Comparator<String> byLength = (s1, s2) -> s1.length() - s2.length();
List<String> result = list.stream()
.filter(lowerThanOrEqualToFour.and(greaterThanOrEqualToThree))
.sorted(byLastLetter.thenComparing(byLength))
.limit(4)
.collect(Collectors.toList());
  并行处理
  用它来遍历文件列表则再常见不过了:
public static void main(String[] args) {
File[] files = new File("c:/windows").listFiles();
Stream.of(files)
.parallel()
.forEach(Sample::process);
}
private static void process(File file) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
System.out.println("Processing -> " + file);
}
  注意上面给出这个示例的同时,也暴露了并行处理的一些缺点。 Stream API进阶
  映射
  遍历文件后返回一个FileSize 对象:
class FileSize {
private final File file;
private final Long size;
FileSize(File file, Long size) {
this.file = file;
this.size = size;
}
File getFile() {
return file;
}
Long getSize() {
return size;
}
String getName() {
return getFile().getName();
}
String getFirstLetter() {
return getName().substring(0, 1);
}
@Override
public String toString() {
return Objects.toStringHelper(this)
.add("file", file)
.add("size", size)
.toString();
}
}
  最终进行映射的代码:
  File[] files = new File("c:/windows").listFiles();
  List<FileSize> result = Stream.of(files)
  .map(FileSize::new)
  .collect(Collectors.toList());
  分组:
  按文件名的第一个字母将FileSize对象分组
  Map<String, List<FileSize>> result = Stream.of(files)
  .map(FileSize::new)
  .collect(Collectors.groupingBy(FileSize::getFirstLetter));
  Reduce
  找出文件夹下的最大最小文件:
  Optional<FileSize> filesize = Stream.of(files)
  .map(FileSize::new)
  .reduce((fs1, fs2) -> fs1.getSize() > fs2.getSize() ? fs1 : fs2);
  如果你不需要FileSize对象,只需要一个数值的话:
  OptionalLong max = Stream.of(files)
  .map(FileSize::new)
  .mapToLong(fs -> fs.getSize())
  .max();

posted @ 2014-06-30 18:27 顺其自然EVO 阅读(163) | 评论 (0)编辑 收藏

Java算法-冒泡排序

 思想:
  冒泡排序(BubbleSort)的基本概念是:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。
  至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。
  由于在排序过程中总是小数往前放,大数往后放,相当于气泡往上升,所以称作冒泡排序。
  用二重循环实现,外循环变量设为i,内循环变量设为j。假如有10个数需要进行排序,则外循环重复9次,内循环依次重复9,8,...,1次。每次进行比较的两个元素都是与内循环j有关的,它们可以分别用a[j]和a[j+1]标识,i的值依次为1,2,...,9,对于每一个i,j的值依次为1,2,...10-i。
  代码:
public static void main(String[] args) {
int[] i = {1001,596,403,39,23,12,9,6,5,4,3,1};
bubbleSort(i);
}
private static void show(int[] x) {
for (int i:x) {
System.out.print(i + " ");
}
System.out.println();
}
public static void bubbleSort(int[] a) {
int temp;
show(a);
for (int i = a.length - 1;i > 0;i--) {
System.out.println("----------Round " + (a.length - i) + "-----------");
for (int j = 0;j < i;j++) {
if (a[j] > a[j + 1]) {
temp = a[j];
a[j] = a[j + 1];
a[j + 1] = temp;
}
show(a);
}
}
}
 结果:
1001 596 403 39 23 12 9 6 5 4 3 1
----------Round 1-----------
596 1001 403 39 23 12 9 6 5 4 3 1
596 403 1001 39 23 12 9 6 5 4 3 1
596 403 39 1001 23 12 9 6 5 4 3 1
596 403 39 23 1001 12 9 6 5 4 3 1
596 403 39 23 12 1001 9 6 5 4 3 1
596 403 39 23 12 9 1001 6 5 4 3 1
596 403 39 23 12 9 6 1001 5 4 3 1
596 403 39 23 12 9 6 5 1001 4 3 1
596 403 39 23 12 9 6 5 4 1001 3 1
596 403 39 23 12 9 6 5 4 3 1001 1
596 403 39 23 12 9 6 5 4 3 1 1001
----------Round 2-----------
403 596 39 23 12 9 6 5 4 3 1 1001
403 39 596 23 12 9 6 5 4 3 1 1001
403 39 23 596 12 9 6 5 4 3 1 1001
403 39 23 12 596 9 6 5 4 3 1 1001
403 39 23 12 9 596 6 5 4 3 1 1001
403 39 23 12 9 6 596 5 4 3 1 1001
403 39 23 12 9 6 5 596 4 3 1 1001
403 39 23 12 9 6 5 4 596 3 1 1001
403 39 23 12 9 6 5 4 3 596 1 1001
403 39 23 12 9 6 5 4 3 1 596 1001
----------Round 3-----------
39 403 23 12 9 6 5 4 3 1 596 1001
39 23 403 12 9 6 5 4 3 1 596 1001
39 23 12 403 9 6 5 4 3 1 596 1001
39 23 12 9 403 6 5 4 3 1 596 1001
39 23 12 9 6 403 5 4 3 1 596 1001
39 23 12 9 6 5 403 4 3 1 596 1001
39 23 12 9 6 5 4 403 3 1 596 1001
39 23 12 9 6 5 4 3 403 1 596 1001
39 23 12 9 6 5 4 3 1 403 596 1001
----------Round 4-----------
23 39 12 9 6 5 4 3 1 403 596 1001
23 12 39 9 6 5 4 3 1 403 596 1001
23 12 9 39 6 5 4 3 1 403 596 1001
23 12 9 6 39 5 4 3 1 403 596 1001
23 12 9 6 5 39 4 3 1 403 596 1001
23 12 9 6 5 4 39 3 1 403 596 1001
23 12 9 6 5 4 3 39 1 403 596 1001
23 12 9 6 5 4 3 1 39 403 596 1001
----------Round 5-----------
12 23 9 6 5 4 3 1 39 403 596 1001
12 9 23 6 5 4 3 1 39 403 596 1001
12 9 6 23 5 4 3 1 39 403 596 1001
12 9 6 5 23 4 3 1 39 403 596 1001
12 9 6 5 4 23 3 1 39 403 596 1001
12 9 6 5 4 3 23 1 39 403 596 1001
12 9 6 5 4 3 1 23 39 403 596 1001
----------Round 6-----------
9 12 6 5 4 3 1 23 39 403 596 1001
9 6 12 5 4 3 1 23 39 403 596 1001
9 6 5 12 4 3 1 23 39 403 596 1001
9 6 5 4 12 3 1 23 39 403 596 1001
9 6 5 4 3 12 1 23 39 403 596 1001
9 6 5 4 3 1 12 23 39 403 596 1001
----------Round 7-----------
6 9 5 4 3 1 12 23 39 403 596 1001
6 5 9 4 3 1 12 23 39 403 596 1001
6 5 4 9 3 1 12 23 39 403 596 1001
6 5 4 3 9 1 12 23 39 403 596 1001
6 5 4 3 1 9 12 23 39 403 596 1001
----------Round 8-----------
5 6 4 3 1 9 12 23 39 403 596 1001
5 4 6 3 1 9 12 23 39 403 596 1001
5 4 3 6 1 9 12 23 39 403 596 1001
5 4 3 1 6 9 12 23 39 403 596 1001
----------Round 9-----------
4 5 3 1 6 9 12 23 39 403 596 1001
4 3 5 1 6 9 12 23 39 403 596 1001
4 3 1 5 6 9 12 23 39 403 596 1001
----------Round 10-----------
3 4 1 5 6 9 12 23 39 403 596 1001
3 1 4 5 6 9 12 23 39 403 596 1001
----------Round 11-----------
1 3 4 5 6 9 12 23 39 403 596 1001

posted @ 2014-06-30 18:26 顺其自然EVO 阅读(135) | 评论 (0)编辑 收藏

如何提交高质量的缺陷报告单?

 关于如何提交高质量的缺陷报告单,本人总结了如下几点:
  1、 缺陷的概要描述要清晰准确,要使相关开发负责人员能够一目了然问题是什么。
  2、 一个完整的缺陷报告单,必须包含其必要的元素信息,例如:概要描述,缺陷发现人,测试环境,浏览器,缺陷重现步骤,严重等级,指派人,所属功能模块等等,必要元素信息必须描述全面清楚。
  3、 缺陷的重现步奏必须描写清晰明了,使相关开发负责人能够根据重现步骤准确的重现所提交的缺陷,使其定位缺陷的原因所在。
  4、 指派给人一定要明确,如知道缺陷是所属具体的某一个开发人员时,应该直接指派给对应的负责人,这样就能减少中间分配环节的时间。
  5、 测试数据,测试的数据作为重现缺陷的一个重要元素信息,一定要将测试时所使用的信息给描写清楚准确。让开发人员根据测试所提供的测试数据准确重现缺陷。
  6、 附件截图信息,附件或截图信息能让开发人员能够一目了然的清楚问题的所在,所以必要的时候提供附件或者截图信息也非常的重要。
  7、描述缺陷内容的语气,在进行缺陷单书写时,尽量使用专业术语(体现测试的专业性),其次注意书写缺陷报告单时不要带有个人客观的语气内容,以免影响开发和测试人员之间的关系。
版权声明:本文出自 lp20105203344 的51Testing软件测试博客:http://www.51testing.com/?421250
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。

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

性能测试工具Grinder

什么是Grinder
  Grinder是一个JavaTM负载测试框架,支持分布式测试,且是开源的。
  官网及下载:SourceForge.net.
  The Grinder processes
  Grinder是一个将测试脚本运行在多个机器上的框架。Grinder框架由三个process(或program)组成: worker processes, agent processes, 和console. 每种process的职责如下:
  Worker processes
  解释Jython测试脚本,并启动worker线程进行测试
  Agent processes
  管理 worker processes
  The console
  协调其他的 processes
  数据的收集,处理及显示
  测试脚本的编辑及分发
  Grinder由Java编写,其中每个processes都是一个java虚拟机(JVM)。
  在进行负载测试时,应该在每个测试机上启动一个代理线程。代理进程启动的所有worker进程都可以由同一个控制台进行控制和监视。在每个测试机上都启动多个代理进程是非常没有必要的,但是如果你愿意也可以这样做。
 Tests and test scripts 测试及测试脚本
  在一个典型的测试场景中,测试脚本会被执行很多遍。每个工作进程都包含若干个工作线程,每个工作线程都会调用测试脚本若干次。测试脚本的一次单独执行称作一个run。
  测试脚本的获取有两种方式:
  1.        手工编写grinder测试脚本。参考:Script Gallery。
  2.        TCP代理录制测试脚本
  启动代理命令:net.grinder.TCPProxy –console –http > grinder.py
  设置IE代理:
  在IE中打开设置窗口:Tools -> Internet Options -> Connections ->Local Area Network Settings -> advanced... 按上面控制台输出的信息填入代理。
  打开要测试的网站或工程,对网站或工程的操作会被自动记录到当前目录的grinder.py脚本中。
  Network communication网络通讯
  每个worker process都会与console建立一个网络连接来报告统计数据。
  每个agent process都与console建立一个连接来接收命令,然后传递给它的worker process。
  Console通过一个特殊的地址和端口来监听这两种连接。默认情况下,地址是运行console的机器的本地地址,端口是6372。
  如果agent process连接console失败,或者 grinder.useConsole属性被设置为false,agent将不需要console的控制而独立地运行,并自动启动worker process开始测试。Worker process运行至完成都不再向console报告。如果你不想受console的干扰而快速的开始测试,上面的方式是非常有用的。
  Note
  更改console地址的方法:设置grinder.properties文件中的grinder.consoleHost和grinder.consolePort。
  输出
  每个worker process都会写日志信息到文件out-host-n.log中,其中host是主机名,n是worker process数量。
  Error信息在文件error-host-n.log中。如果没有error产生,将不会创建该文件。
  测试结果在文件data-host-n.log中。该文件可以导入电子表格工具中,例如Microsoft ExcelTM,以便进一步的分析。
 最后的统计汇总数据(out-*文件中)形式如下:
Final statistics for this process:
Successful  Errors   Mean Test  Test Time Standard
Tests                                 Time(ms)    Deviation (ms)
Test 0     25        0       255.52     22.52
Test 1     25        0       213.40     25.15
Test 2     25        0       156.80     20.81     "Image"
Test 3     25        0       90.48      14.41
Test 4     25        0       228.68     23.97      "Login page"
Test 5     25        0       86.12      12.53  "Security check"
Test 6     25        0       216.20     8.89
Test 7     25        0       73.20      12.83
Test 8     25        0       141.92     18.36
Test 9     25        0       104.68     19.86     "Logout page"
Totals        250           0             156.70       23.32
  测试过程中,Console会动态显示简单的统计信息。另外,plug-in和高级测试脚本可以提供额外的数据统计,例如:HTTP plug-in 添加了对response消息体的内容长度统计。
  每个测试有两种可能结果:
  Success.
  Error.
  其中Total, Mean, 以及 Standard Deviation 都是基于成功的测试进行计算的。
  如何启动 Grinder开始测试?
  启动Grinder进行测试包括以下步骤:
  创建 grinder.properties 文件.
  该文件指定一般的控制信息(例如:worker process如何与console通信,使用的worker process数等),以及要执行的Jython测试脚本。
  设置系统环境变量: CLASSPATH 包含 grinder.jar 文件, 该文件应该在 lib 文件夹下。
  在其中一个测试机上启动 console :
  java net.grinder.Console
  对每一个测试机,执行步骤1和步骤2,然后启动一个agent process:
  java net.grinder.Grinder
  agent将会在本地文件夹中寻找grinder.properties文件。
  Jython脚本通常存放在properties文件同级目录下。
  另外,可以通过参数的方式明确指定properties文件,例如:
  java net.grinder.Grinder myproperties
  Note
  如果对console比较熟悉,可以通过console来编辑以及分发properties文件和测试脚本,这样就不必将他们分别拷贝到每个测试机上。
  下面的一些脚本是在Unix/Linux 下,用来启动grinder agents, console 和 录制HTTP脚本的TCPProxy。
Windows
setGrinderEnv.cmd:
·                      set GRINDERPATH=(full path to grinder install directory)
·                      set GRINDERPROPERTIES=(full path to grinder.properties)\grinder.properties
·                      set CLASSPATH=%GRINDERPATH%\lib\grinder.jar;%CLASSPATH%
·                      set JAVA_HOME=(full path to java install directory)
·                      PATH=%JAVA_HOME%\bin;%PATH%
startAgent.cmd:
·                      call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd
·                      echo %CLASSPATH%
·                      java -cp %CLASSPATH% net.grinder.Grinder %GRINDERPROPERTIES%
startConsole.cmd:
·                      call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd
·                      java -cp %CLASSPATH% net.grinder.Console
startProxy.cmd:
·                      call (path to setGrinderEnv.cmd)\setGrinderEnv.cmd
·                      java -cp %CLASSPATH% net.grinder.TCPProxy -console -http > grinder.py
Unix
setGrinderEnv.sh:
·                      #!/usr/bin/ksh
·                      GRINDERPATH=(full path to grinder install directory)
·                      GRINDERPROPERTIES=(full path to grinder.properties)/grinder.properties
·                      CLASSPATH=$GRINDERPATH/lib/grinder.jar:$CLASSPATH
·                      JAVA_HOME=(full path to java install directory)
·                      PATH=$JAVA_HOME/bin:$PATH
·                      export CLASSPATH PATH GRINDERPROPERTIES
startAgent.sh:
·                      #!/usr/bin/ksh
·                      . (path to setGrinderEnv.sh)/setGrinderEnv.sh
·                      java -cp $CLASSPATH net.grinder.Grinder $GRINDERPROPERTIES
startConsole.sh:
·                      #!/usr/bin/ksh
·                      . (path to setGrinderEnv.sh)/setGrinderEnv.sh
·                      java -cp $CLASSPATH net.grinder.Console
startProxy.sh:
·                      #!/usr/bin/ksh
·                      . (path to setGrinderEnv.sh)/setGrinderEnv.sh
·                      java -cp $CLASSPATH net.grinder.TCPProxy -console -http > grinder.py

posted @ 2014-06-30 18:21 顺其自然EVO 阅读(746) | 评论 (0)编辑 收藏

在iOS8上使用TestFlight进行Beta测试

  什么是Grinder
  Grinder是一个JavaTM负载测试框架,支持分布式测试,且是开源的。
  官网及下载:SourceForge.net.
  The Grinder processes
  Grinder是一个将测试脚本运行在多个机器上的框架。Grinder框架由三个process(或program)组成: worker processes, agent processes, 和console. 每种process的职责如下:
  Worker processes
  解释Jython测试脚本,并启动worker线程进行测试
  Agent processes
  管理 worker processes
  The console
  协调其他的 processes
  数据的收集,处理及显示
  测试脚本的编辑及分发
  Grinder由Java编写,其中每个processes都是一个java虚拟机(JVM)。
  在进行负载测试时,应该在每个测试机上启动一个代理线程。代理进程启动的所有worker进程都可以由同一个控制台进行控制和监视。在每个测试机上都启动多个代理进程是非常没有必要的,但是如果你愿意也可以这样做。
 使用这些新功能有几点注意事项。
  第一点并且最重要的一点是,一个应用在开放给beta测试人员前,必须先通过一个审核流程。这对于一些开发人员来说是个问题:Ole Begemann提到,长达几天的审核时间无益于创建“一个高效的beta版本发布流程”。苹果好像也意识到了这对开发人员来说是个潜在的问题,他们已经考虑了一项更宽松的政策,允许“无需苹果审核就可以给beta测试人员发布更新版本,除非这个更新版本包含重大修改”。如果更新版本包含了重大修改,开发人员必须“通过iTunes Connect通知苹果,申请重新审核他们的应用”。
  还有一点要引起注意,那就是测试人员只能拿到应用最新的版本。Nick Arnott为iMore网站写了篇文章,他注意到在苹果的演示视频中,除了最新的版本,其他版本都标记为“未激活”状态了。目前尚不清楚Beta测试人员是否能拿到老版本,很多人恐怕都难以接受这个问题,因为beta测试人员如果遇到了致命的问题,他们可能会需要回退到老版本。
  最后一点是,我们必须注意现在发布的TestFlight只支持iOS 8了,所以开发人员如果还是想支持老版本的iOS或Android,那么就不能用TestFlight了。他们有两个其他的选择,HockeyApp和Crashlytics。

posted @ 2014-06-30 18:19 顺其自然EVO 阅读(289) | 评论 (0)编辑 收藏

Selenium基本使用与注意事项

#coding=utf-8
from selenium import webdriver
import time
import random
driver = webdriver.Chrome()
driver.get('url')
driver.find_element_by_name('tb_uname').send_keys('username')
driver.find_element_by_name('tb_pwd').send_keys('password')
driver.find_element_by_name('tb_code').send_keys('')
time.sleep(10)
driver.find_element_by_name('btnSave').click()
driver.find_element_by_link_text('xxxx').click()
driver.find_element_by_link_text('yyyy').click()
length = len(driver.find_element_by_xpath("//div[@id='list']").find_elements_by_link_text('编辑'))
for i in range(0,length):
l = random.randint(1,9)
editions = driver.find_element_by_xpath("//div[@id='list']").find_elements_by_link_text('编辑')
edit = editions[i]
edit.click()
driver.find_element_by_id('txtnewstype3').click()
driver.find_element_by_xpath('//ul[@id="typeoption3"]/li[%d]'%l).click()
time.sleep(1)
driver.find_element_by_id('ckhead').click()
time.sleep(1)
driver.find_element_by_id('ckpush').click()
time.sleep(1)
driver.find_element_by_id('btnsave').click()
time.sleep(1)
driver.switch_to_alert().accept()
driver.back()
time.sleep(1)
driver.find_element_by_xpath("//div[@id='list']").find_element_by_link_text('删除').click()
  首先注意事项
  有时页面还没加载出来,脚本找不到元素,就会报错,所以添加思考时间是非常必要的,切记。
  进入一个页面后,简单实用back()函数,再进行查找元素时,会报错,所以要将不断来回查找的元素放进循环体内
  driver.switch_to_alert().accept() 处理弹窗"接受"作用
  l = random.randint(1,9) 随机函数,根据用例要求进行实用
  '[%d]'%l 直白的理解就是将后面 l 的值传递给%d(整数)
  find_element_by_link_text 和 find_elements_by_link_text 有区别,后者主要是查找整个页面相同的函数,即可迭代。

posted @ 2014-06-30 18:17 顺其自然EVO 阅读(257) | 评论 (0)编辑 收藏

手机UI自动化测试工具NativeDriver VS Robotium

最近在调研手机端的自动化测试工具,之前看到了Robotium这个工具也写了几个用例,后面发现了NativeDriver工具,也写了几个 例子,下面主要从官方介绍以及写例子的过程中发现的一些问题对比一下两种工具的优缺点吧,也是刚开始做自动化测试不久,暂时还没有了解工具底层的一些东 西,以下仅是自己个人观点,如果有不全面的欢迎大家评论补充讨论。现在打算使用NativeDriver工具来进行手机端UI自动测试。
  NativeDriver:
  官方地址:http://code.google.com/p/nativedriver/
  优点:
  1、跨平台,android平台的源代码已经公开,IOS的不久也将要发布,windows平台的在计划中,以后针对不同的平台都可以使用相同的语言和相同的API来写用例。
  2、使用WebDriver API(selenium2.0也加入了WebDriver )进行的扩展,对于熟悉WebDriver的用户,上手会更加的快(PS:还不熟悉WebDriver,有空学习一下)
  3、类似于selenium RC的方式来运行测试程序,这个可以看下面的NativeDriver架构图,测试程序通过http+json访问模拟器上的server,然后进行相应的模拟操作
  4、元素查找可以直接使用通过hierarchyviewer工具识别出来了资源ID来进行元素查找定位
  5、支持WebView控件
  缺点:
  1、被测程序需要加入工具提供的server-standalone.jar,以及修改AndroidManifest.xml文件后专门打build用于测试,具体见:
  http://code.google.com/p/nativedriver/wiki/AndroidMakeAnAppTestable
  2、现在NativeDriver提供的API还是有些少,不过可以自己扩展一下。
  3、貌似没发现wait相关的api,需要自己来封装一下来等待响应控件的操作了。
  4、这是在写测试用例的时候发现的,不知道是哪里的问题,先就算作缺点吧,比如对文本框输入文字,如果当前文本框没有获取焦点,是输入不了文字的,sendKeys输入之前需要click一下获取到焦点。
  WebElement passWord = driver.findElement(By.id("PassWord"));//找到资源id为PassWord的控件
  passWord.clear();//清除控件文字
  passWord.click();//点击选中控件,此时会获取到焦点
  passWord.sendKeys("123");//控件中输入内容
  5、由于是刚推出来,网上的资料还是比较少的,需要自己去摸索,而且官方API也没有,还好有源代码可以看一下

 Robotium:
  官方地址:http://code.google.com/p/robotium/
  优点:
  1、提供的API相应的还是比较丰富的
  2、网上相关资料稍微会多一些
  缺点:
  1、 测试程序也需要生产APK文件,安装到模拟器或者设备上,所以如果被测程序和测试程序签名不一样是测试不了的,这就需要测试之前我们去修改被测程序的签 名。不过按照计划,后续的版本会提供类似于selenium RC模式的,到时候可能会解决这个问题,但是还不知道什么时候发布。
  2、不支持跨平台
  3、API中很多使用控件的位置(index索引)来查找,这样子对以后用例的维护会有些不方便。同时API中有按照id来查找的使用的确是R.java自动生成的文件中的id,但是通过工具只能识别到资源控件id,这个还需要自己通过资源控件id去查找一下才行

posted @ 2014-06-30 18:16 顺其自然EVO 阅读(393) | 评论 (0)编辑 收藏

仅列出标题
共394页: First 上一页 93 94 95 96 97 98 99 100 101 下一页 Last 
<2024年11月>
272829303112
3456789
10111213141516
17181920212223
24252627282930
1234567

导航

统计

常用链接

留言簿(55)

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜