用心纪录,用心发现。

发布新日志

  • Python中字典(dict)和列表(list)的排序方法实例

    2014-09-03 17:53:49

    一、对列表(list)进行排序

    推荐的排序方式是使用内建的sort()方法,速度最快而且属于稳定排序

    复制代码代码如下:

    >>> a = [1,9,3,7,2,0,5]
    >>> a.sort()
    >>> print a
    [0, 1, 2, 3, 5, 7, 9]
    >>> a.sort(reverse=True)
    >>> print a
    [9, 7, 5, 3, 2, 1, 0]
    >>> b = ['e','a','be','ad','dab','dbc']
    >>> b.sort()
    >>> print b
    ['a', 'ad', 'be', 'dab', 'dbc', 'e']

    对列表的排序是遵循DSU(decorate-sort-undecorate)模式的,序列是安装条目的顺序进行比较的,对刚刚例子中的字符串来说,就是按照从左到右的顺序,逐个字符进行比较,一旦得出结果就停止比较。

    二、对字典(dict)进行排序

    其实字典(dict)是一个无序序列,谈不上排序,我们只能按照字典的键/值进行排序,然后让对应值/键也处于同样的顺序
    任何对字典的排序问题,都要最终归结为对字典(dict)的键(key)或者值(value)组成的列表(list)的排序

    1、按字典(dict)的键进行排序[1]

    复制代码代码如下:

    def sortedDictValues(adict,reverse=False):
     keys = adict.keys()
     keys.sort(reverse=reverse)
     return [adict[key] for key in keys]

    如果需要同时返回键和值的话,之用将最后的return语句改为:
    复制代码代码如下:
    return [(key,adict[key]]) for key in keys]

    还有一种书写简单的方法,就是使用内置的sorted()方法进行排序:
    复制代码代码如下:

    >>> d = {'c':1,'e':'5','b':7}
    >>> sorted(d.items())
    [('b', 7), ('c', 1), ('e', '5')]

    不过性能会有些许的下降,如果很苛求性能,还是使用原生对list.sort()方法比较好

    2、按字典(dict)的值进行排序[2]

    复制代码代码如下:

    def sorted_dict(container, keys, reverse):
     """返回 keys 的列表,根据container中对应的值排序"""
     aux = [ (container[k], k) for k in keys]
     aux.sort()
     if reverse: aux.reverse()
     return [k for v, k in aux]

    同样可以用sorted()方法实现同样的功能:
    复制代码代码如下:
    sorted(d.items(), key=lambda d:d[1], reverse=True)

    三、结语

    通过以上代码的分析,大致总结处以下几条原则:
    * 对字典的排序,最终都要归结为对字典的键或者值组成的列表的排序
    * 对列表的排序,优先使用内置的list.sort()方法

  • Python的lambda匿名函数

    2014-08-28 15:55:05

    lambda函数也叫匿名函数,即,函数没有具体的名称。先来看一个最简单例子:

    def f(x):
    return x**2
    print f(4)

    Python中使用lambda的话,写成这样

    g = lambda x : x**2
    print g(4)

     

    lambda表达式在很多编程语言都有对应的实现。比如C#:

    var g = x => x**2
    Console.WriteLine(g(4))

    那么,lambda表达式有什么用处呢?很多人提出了质疑,lambda和普通的函数相比,就是省去了函数名称而已,同时这样的匿名函数,又不能共享在别的地方调用。其实说的没错,lambda在Python这种动态的语言中确实没有起到什么惊天动地的作用,因为有很多别的方法能够代替lambda。同时,使用lambda的写法有时显得并没有那么pythonic。甚至有人提出之后的Python版本要取消lambda。

     

    回过头来想想,Python中的lambda真的没有用武之地吗?其实不是的,至少我能想到的点,主要有:

    1. 使用Python写一些执行脚本时,使用lambda可以省去定义函数的过程,让代码更加精简。

    2. 对于一些抽象的,不会别的地方再复用的函数,有时候给函数起个名字也是个难题,使用lambda不需要考虑命名的问题。

    3. 使用lambda在某些时候让代码更容易理解。

    lambda基础

    lambda语句中,冒号前是参数,可以有多个,用逗号隔开,冒号右边的返回值。lambda语句构建的其实是一个函数对象,见证一下:

    g = lambda x : x**2
    print g
    <function <lambda> at 0x00AFAAF0>

    C#3.0开始,也有了lambda表达式,省去了使用delegate的麻烦写法。C#中的lambda表达式关键字是=>,看下面的一个例子:

    var array = new int[] {2, 3, 5, 7, 9};
    var result = array.Where(n => n > 3); // [5, 6, 9]

     

    C#使用了扩展方法,才使得数组对象拥有了像Where,Sum之类方便的方法。Python中,也有几个定义好的全局函数方便使用的,他们就是filter, map, reduce。

    >>> foo = [2, 18, 9, 22, 17, 24, 8, 12, 27]
    >>>
    >>> print filter(lambda x: x % 3 == 0, foo)
    [18, 9, 24, 12, 27]
    >>>
    >>> print map(lambda x: x * 2 + 10, foo)
    [14, 46, 28, 54, 44, 58, 26, 34, 64]
    >>>
    >>> print reduce(lambda x, y: x + y, foo)
    139

     

     

    非lambda不可?

    上面例子中的map的作用,和C#的Where扩展方法一样,非常简单方便。但是,Python是否非要使用lambda才能做到这样的简洁程度呢?在对象遍历处理方面,其实Python的for..in..if语法已经很强大,并且在易读上胜过了lambda。比如上面map的例子,可以写成:

    print [x * 2 + 10 for x in foo]

    非常的简洁,易懂。filter的例子可以写成:

    print [x for x in foo if x % 3 == 0]

    同样也是比lambda的方式更容易理解。

    所以,什么时候使用lambda,什么时候不用,需要具体情况具体分析,只要表达的意图清晰就好。一般情况下,如果for..in..if能做的,我都不会选择lambda。

    lambda broken?

    在数学教学中,经常会使用到lambda,比如有一位老兄就遇到这样一个问题。他想创建一个函数数组fs=[f0,...,f9] where fi(n)=i+n. 于是乎,就定义了这么一个lambda函数:

    fs = [(lambda n: i + n) for i in range(10)]

    但是,奇怪的是,

    >>> fs[3](4)
    13
    >>> fs[4](4)
    13
    >>> fs[5](4)
    13

    结果并没有达到这位老兄的预期,预期的结果应该是:

    >>> fs[3](4)
    7
    >>> fs[4](4)
    8
    >>> fs[5](4)
    9

    问题其实出在变量i上。上面的代码换个简单的不使用lambda的缩减版本:

    i = 1
    def fs(n):
    return n + i
    print fs(1) # 2
    i = 2
    print fs(1) # 3

    可见,上面没有达到预期的原因是lambda中的i使用的是匿名函数外的全局变量。修改一下:

    fs = [(lambda n, i=i : i + n) for i in range(10)]
    >>> fs[3](4)
    7
    >>> fs[4](4)
    8
    >>> fs[5](4)
    9

  • python with关键字用法

    2014-08-28 15:34:54

    with从Python 2.5就有,需要from __future__ import with_statement。
    python 2.6开始,成为默认关键字。
    在What's new in python2.6/3.0中,明确提到:
    The 'withstatement is a control-flow structure whose basic structure is:
    with expression [as variable]: with-block
    也就是说with是一个控制流语句,跟if/for/while/try之类的是一类的,with可以用来简化try finally代码,看起来可以比try finally更清晰。
    这里新引入了一个"上下文管理协议"context management protocol,实现方法是为一个类定义__enter__和__exit__两个函数。
    with expresion as variable的执行过程是,首先执行__enter__函数,它的返回值会赋给as后面的variable,想让它返回什么就返回什么,只要你知道怎么处理就可以了,如果不写as variable,返回值会被忽略。
    然后,开始执行with-block中的语句,不论成功失败(比如发生异常、错误,设置sys.exit()),在with-block执行完成后,会执行__exit__函数。
    这样的过程其实等价于:
    try:
    执行 __enter__的内容
    执行 with_block.
    finally:
    执行 __exit__内容
    只不过,现在把一部分代码封装成了__enter__函数,清理代码封装成__exit__函数。
    我们可以自己实现一个例子:
    import sys
    class test:
    def __enter__(self):
           print("enter")
           return 1
    def __exit__(self,*args):
           print("exit")
           return True
    with test() as t:
    print("t is not the result of test(), it is __enter__ returned")
    print("t is 1, yes, it is {0}".format(t))
    raise NameError("Hi there")
    sys.exit()
    print("Never here")
    注意:
    1,t不是test()的值,test()返回的是"context manager object",是给with用的。t获得的是__enter__函数的返回值,这是with拿到test()的对象执行之后的结果。t的值是1.
    2,__exit__函数的返回值用来指示with-block部分发生的异常是否要re-raise,如果返回False,则会re-raise with-block的异常,如果返回True,则就像什么都没发生。
    符合这种特征的实现就是符合“上下文管理协议”了,就可以跟with联合使用了。
    as关键字的另一个用法是except XXX as e,而不是以前的except XXX,e的方式了。
    此外,还可以使用contextlib模块中的contextmanager,方法是:
    @contextmanager
    ...
    yield something
    ...
    的方式,具体需要看看文档和手册了。
    yield的用法还是很神奇的,一句两句搞不清楚,如果您已经弄懂,看看文档就明白了,如果不懂yield,根据自己的需要去弄懂或者干脆不理他也可以,反正用到的时候,您一定回去搞懂的:-
    其实with很像一个wrapper或者盒子,把with-block部分的代码包装起来,加一个头,加一个尾,头是__enter__,尾是__exit__,无论如何,头尾都是始终要执行的。


    有一篇详细的介绍在:http://effbot.org/zone/python-with-statement.htm

     

    我简单翻译一下其中的要点:

    如果有一个类包含  __enter__ 方法和 __exit__ 方法,像这样:
    class  controlled_execution:
           def__enter__(self):
                  set things up
                  return thing
            def__exit__(self, type, value, traceback):
                  tear things down
    那么它就可以和with一起使用,像这样:

    with controlled_execution() as thing:
    some code
        当with语句被执行的时候,python对表达式进行求值,对求值的结果(叫做“内容守护者”)调用__enter__方法,并把__enter__
    方法的返回值赋给as后面的变量。然后python会执行接下来的代码段,并且无论这段代码干了什么,都会执行“内容守护者”的__exit__
    方法。

           作为额外的红利,__exit__方法还能够在有exception的时候看到exception,并且压制它或者对它做出必要的反应。要压制exception,只需要返回一个true。比如,下面的__exit__方法吞掉了任何的TypeError,但是让所有其他的exceptions通过:

    def__exit__(self, type, value, traceback):
    return isinstance(value, TypeError)

    在Python2.5中,file object拥有__enter__和__exit__方法,前者仅仅是返回object自己,而后者则关闭这个文件:
    >>> f = open("x.txt")
    >>> f
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.__enter__()
    <open file 'x.txt', mode 'r' at 0x00AE82F0>
    >>> f.read(1)
    'X'
    >>> f.__exit__(None, None, None)
    >>> f.read(1)
    Traceback (most recent call last):
    File "<stdin>", line 1, in <module>
    ValueError: I/O operation on closed file
    这样要打开一个文件,处理它的内容,并且保证关闭它,你就可以简简单单地这样做:
    with open("x.txt") as f:
    data = f.read()
    do something with data

    我的补充:
    数据库的连接好像也可以和with一起使用,我在一本书上看到以下内容:
    conn = sqlite.connect("somedb")
    with conn:
        conn.execute("insert into sometable values (?,?)",("foo","bar"))
    在这个例子中,commit()是在所有with数据块中的语句执行完毕并且没有错误之后自动执行的,如果出现任何的异常,将执行rollback()
    操作,再次提示异常
  • Python基础学习篇——Global全局变量的使用

    2014-08-28 15:24:38

    为了测试Python中全局变量的使用,我们试图撰写以下几个例子进行说明:
    #第一例子,是用来验证一个最基础的全局变量与局部变量的区别,内容如下:
    #-*- coding: cp936 -*-
    global a 
    def a():
     a=2
     a+=1
     print a
     #注意这里没有使用return a 
    def do():
     a()
     #并把a方法的value(a)进行运算
     a+=1
    #我们写一个main函数来调用这个do的过程
    if __name__ = "__main__":
     do()
     print a
    #我们在Python(idle)中,运行程序F5
    #程序出现调试错误:local variable 'a' referenced before assignment
    #由此,我们可以看出局部变量在方法中是不能传递的,为了能够使用几个方法返回的
    #值,并在do()这个函数中进行运算,我们引入了全局变量global a,现在我们对以上
    #的程序做出进行以下调整
    #================================ RESTART ================================
    global a 
    def a():
    #这里我们引用设置的全局变量a,写在函数中
     global a
     a = 2
     a += 1
     #预期的a = 3
     print a
    def do():
    #这里由于我们需要对定义的全局变量进行重新计算,我们这次引用a
    global a
     a()
     a+=1
    if __name__ = "__main__":
     do()
    #如果我们需要在最后的main函数中,输出由do()函数最终计算的变量a,则我们必须在这里在此引用这个变量a
     global a 
     #预期的值4
     print a 
    #现在我们再次运行程序这时,我们看到的数值结果与预期结果一致,为3,4
    #================================ RESTART ================================
    #总结:全局变量的使用是为了使我们在一个类或一个函数中使用由函数返回的变量,
    #并进行复杂的计算过程而使用。而对于一个函数的局部变量,则只在一个函数内部是
    #可使用的,而如果需要跨越不同的函数或者类则需要在基础函数中返回一个该值,在
    #下一个函数中运行其方法才能获取该值进行计算,如果程序不复杂在一个类中可以解决
    #全局变量会为我们节省不少的时间,以及内存空间。
  • python中'\'的用法

    2014-08-06 15:35:15

    1.换行(与Bash效果相同)

    ' this is the frist sentence.\

    this is the second sentence.'

    其输出结果为 this is the frist sentence.this is the second sentence.

    又print/

        (s)

    等同于print(s)

     

    2.用于输出 ' \ " 等特殊符号

    'What\'s your name?'  =="what's your name?"

    \\ == 输出"\"

     

    3.用于特殊字母前表示不同的意义

    如 \n  代表换行

    print("this is the frist line \n this is the second line")

    结果

    this is the frist line

    this is the second line

  • Python:list and dictionary

    2014-08-06 14:43:36


    创建列表
    sample_list = ['a',1,('a','b')]

    Python 列表操作
    sample_list = ['a','b',0,1,3]

    得到列表中的某一个值
    value_start = sample_list[0]
    end_value = sample_list[-1]

    删除列表的第一个值
    del sample_list[0]

    在列表中插入一个值
    sample_list[0:0] = ['sample value']

    得到列表的长度
    list_length = len(sample_list)

    列表遍历
    for element in sample_list:
    print(element)

    Python 列表高级操作/技巧

    产生一个数值递增列表
    num_inc_list = range(30)
    #will return a list [0,1,2,...,29]

    用某个固定值初始化列表
    initial_value = 0
    list_length = 5
    sample_list = [ initial_value for i in range(10)]
    sample_list = [initial_value]*list_length
    # sample_list ==[0,0,0,0,0]


    附:python内置类型
    1、list:列表(即动态数组,C++标准库的vector,但可含不同类型的元素于一个list中)
    a = ["I","you","he","she"] #元素可为任何类型。

    下标:按下标读写,就当作数组处理
    以0开始,有负下标的使用
    0第一个元素,-1最后一个元素,
    -len第一个元 素,len-1最后一个元素
    取list的元素数量 
    len(list) #list的长度。实际该方法是调用了此对象的__len__(self)方法。

    创建连续的list
    L = range(1,5) #即 L=[1,2,3,4],不含最后一个元素
    L = range(1, 10, 2) #即 L=[1, 3, 5, 7, 9]

    list的方法
    L.append(var) #追加元素
    L.insert(index,var)
    L.pop(var) #返回最后一个元素,并从list中删除之
    L.remove(var) #删除第一次出现的该元素
    L.count(var) #该元素在列表中出现的个数
    L.index(var) #该元素的位置,无则抛异常 
    L.extend(list) #追加list,即合并list到L上
    L.sort() #排序
    L.reverse() #倒序
    list操作符:,+,*,关键字del
    a[1:] #片段操作符,用于子list的提取
    [1,2]+[3,4] #为[1,2,3,4]。同extend()
    [2]*4 #为[2,2,2,2]
    del L[1] #删除指定下标的元素
    del L[1:3] #删除指定下标范围的元素
    list的复制
    L1 = L #L1为L的别名,用C来说就是指针地址相同,对L1操作即对L操作。函数参数就是这样传递的
    L1 = L[:] #L1为L的克隆,即另一个拷贝。

    list comprehension
    [ <expr1> for k in L if <expr2> ]

    2、dictionary: 字典(即C++标准库的map)
    dict = {'ob1':'computer', 'ob2':'mouse', 'ob3':'printer'}
    每一个元素是pair,包含key、value两部分。key是Integer或string类型,value是任意类型。
    键是唯一的,字典只认最后一个赋的键值。

    dictionary的方法
    D.get(key, 0) #同dict[key],多了个没有则返回缺省值,0。[]没有则抛异常
    D.has_key(key) #有该键返回TRUE,否则FALSE
    D.keys() #返回字典键的列表
    D.values()
    D.items()

    D.update(dict2) #增加合并字典
    D.popitem() #得到一个pair,并从字典中删除它。已空则抛异常
    D.clear() #清空字典,同del dict
    D.copy() #拷贝字典
    D.cmp(dict1,dict2) #比较字典,(优先级为元素个数、键大小、键值大小)
    #第一个大返回1,小返回-1,一样返回0

    dictionary的复制
    dict1 = dict #别名
    dict2=dict.copy() #克隆,即另一个拷贝。

    3、tuple:元组(即常量数组)
    tuple = ('a', 'b', 'c', 'd', 'e')
    可以用list的[],:操作符提取元素。就是不能直接修改元素。

    4、string: 字符串(即不能修改的字符list)
    str = "Hello My friend"
    字符串是一个整 体。如果你想直接修改字符串的某一部分,是不可能的。但我们能够读出字符串的某一部分。
    子字符串的提取
    str[:6]
    字符串包含 判断操作符:in,not in
    "He" in str
    "she" not in str

    string模块,还提供了很多方法,如
    S.find(substring, [start [,end]]) #可指范围查找子串,返回索引值,否则返回-1
    S.rfind(substring,[start [,end]]) #反向查找
    S.index(substring,[start [,end]]) #同find,只是找不到产生ValueError异常
    S.rindex(substring,[start [,end]])#同上反向查找
    S.count(substring,[start [,end]]) #返回找到子串的个数

    S.lowercase()
    S.capitalize() #首字母大写
    S.lower() #转小写
    S.upper() #转大写
    S.swapcase() #大小写互换

    S.split(str, ' ') #将string转list,以空格切分
    S.join(list, ' ') #将list转string,以空格连接

    处理字符串的内置函数
    len(str) #串长度
    cmp("my friend", str) #字符串比较。第一个大,返回1
    max('abcxyz') #寻找字符串中最大的字符
    min('abcxyz') #寻找字符串中最小的字符

    string的转换

    oat(str) #变成浮点数,float("1e-1") 结果为0.1
    int(str) #变成整型, int("12") 结果为12
    int(str,base) #变成base进制整型数,int("11",2) 结果为2
    long(str) #变成长整型,
    long(str,base) #变成base进制长整型,

    字符串的格式化(注意其转义字符,大多如C语言的,略)
    str_format % (参数列表) #参数列表是以tuple的形式定义的,即不可运行中改变
    >>>print ""%s's height is %dcm" % ("My brother", 180)
    #结果显示为 My brother's height is 180cm

    。。。。。。。。。。。。。。。。。。

    list 和 tuple 的相互转化

    tuple(ls) 
    list(ls)

  • Python: file open

    2014-08-04 14:50:56

    from sys import argv
    script, filename = argv
    file = open(filename,'r+')

    open/文件操作
    f=open('/tmp/hello','w')

    #open(路径+文件名,读写模式)

    #读写模式:r只读,r+读写,w新建(会覆盖原有文件),a追加,b二进制文件.常用模式

    如:'rb','wb','r+b'等等

    读写模式的类型有:

    rU 或 Ua 以读方式打开, 同时提供通用换行符支持 (PEP 278)
    w     以写方式打开,
    a     以追加模式打开 (从 EOF 开始, 必要时创建新文件)
    r+     以读写模式打开
    w+     以读写模式打开 (参见 w )
    a+     以读写模式打开 (参见 a )
    rb     以二进制读模式打开
    wb     以二进制写模式打开 (参见 w )
    ab     以二进制追加模式打开 (参见 a )
    rb+    以二进制读写模式打开 (参见 r+ )
    wb+    以二进制读写模式打开 (参见 w+ )
    ab+    以二进制读写模式打开 (参见 a+ )


    注意:

    1、使用'W',文件若存在,首先要清空,然后(重新)创建,

    2、使用'a'模式 ,把所有要写入文件的数据都追加到文件的末尾,即使你使用了seek()指向文件的其他地方,如果文件不存在,将自动被创建。



    f.read([size]) size未指定则返回整个文件,如果文件大小>2倍内存则有问题.f.read()读到文件尾时返回""(空字串)

    file.readline() 返回一行

    file.readline([size]) 返回包含size行的列表,size 未指定则返回全部行

    for line in f: print line #通过迭代器访问

    f.write("hello\n") #如果要写入字符串以外的数据,先将他转换为字符串.

    f.tell() 返回一个整数,表示当前文件指针的位置(就是到文件头的比特数).

    f.seek(偏移量,[起始位置])

    用来移动文件指针

    偏移量:单位:比特,可正可负

    起始位置:0-文件头,默认值;1-当前位置;2-文件尾

    f.close() 关闭文件

    Code:


    #!/usr/bin/env python
    # Filename: using_file.py

    poem='''\Programming is funWhen the work is doneif you wanna make your work also fun: use Python!'''
    f=file('poem.txt','w') # open for 'w'riting
    f.write(poem) # write text to file
    f.close() # close the file
    f=file('poem.txt')

    # if no mode is specified, 'r'ead mode is assumed by default
    while True: 
    line=f.readline() 
    if len(line)==0: # Zero length indicates EOF 
    break 
    print line, 
    # Notice comma to avoid automatic newline added by Python
    f.close() 
    # close the file
  • Python: file.seek

    2014-08-04 14:24:45

    file.seek(0)是重新定位在文件的第0位及开始位置
    好处是不用再打开文件,既可以定位到0的位置或者别的位置,可以对文件进行操作
    如果有一个文件test.txt
    hello
    test!

    file = open("test.txt","rw")
    file.seek(300)
    for i in file:
    print i #不会有值返回,因为是第300个空格

    file.seek(0)
    for i in file
    	print i #有值返回,从0开始
    file.seek(300)
    file.write("test22!")
    for i in file
    	print i
  • URL

    2010-11-10 14:35:35

    http://www.sqaforums.com/postlist.php?Cat=0&Board=UBB6

     

     

  • 如何有效控制需求变更

    2010-07-09 17:03:02

    需求变更对软件开发项目成败有重要影响,既不能一概拒绝客户的变更要求,也不能一味地迁就客户,所以实施需求变更之前必须做好控制。需求变更控制的目的不是控制变更的发生,而是对变更进行管理,确保变更有序进行。

      (1)明确合同约束,建立需求基线

      需求变更给软件开发带来的影响有目共睹,所以在与客户签订合同时,可以增加一些相关条款,如限定客户提出需求变更的时间,规定何种情况的变更可以接受、拒绝或部分接受,还可以规定发生需求变更时必须执行变更管理流程。虽然软件开发合同很难在签订之初就能够精确定义每项需求,单靠合同是帮不上忙的,但也不能忽视合同的约束力。

      明确和树立需求基线是需求变更的依据。在开发过程中,需求确定并经过评审后(客户参与评审),建立第一个需求基线。此后每次变更并经过评审后,都要重新确定新的需求基线,做到小需求可以变更,但大方向要力保不频繁变更。例如,对于项目中的需求,可以实行分级管理,以达到对需求变更的控制和管理。

      (2)建立变更审批流程

      在实践中,人们往往不愿意为小的需求变更去执行正规的需求管理过程,认为降低开发效率,浪费时间。正是这种观念才使需求变更变得不可控,最终导致项目的失败。因此,小的需求变更也要经过正规的需求管理流程,否则会积少成多,积重难返。

      明确需求变更审批环节、审批人员、审批事项、审批流程。这么做的目的有两个:一是将客户下达变更的流程尽可能地规范化,减少张嘴就来的非必要、非紧急、非合理、非高层领导意图的无效变更。二是留下书面依据,为今后可能的成本变更和索赔准备好“变更账”。凡未履行审批程序的“变更”,一律是无效变更不予受理。

      (3)分级管理变更,定时批量处理

      软件开发项目中,“客户永远是对的”和“客户是上帝”并不完全正确,因为在已经签定的项目合同中,任何新需求的变更和增加除了影响项目的正常进行以外,还影响到客户的成本投入收益。因此,用户不断提出对项目进度有重大影响的需求对双赢也并不是好事。

      当遇到客户提出需求,不及时处理可能会使项目不能验收通过时,也不能一味拒绝不予开发。因此,当客户坚持变更新需求时,可以建议客户将新需求按重要和紧迫程度划分档次,作为需求变更评估的一项依据。例如,每周或每两周甚至每月召开一次需求变更专题会议,集中研究处理这些零碎变更事项,主动控制好工作节奏,尽量避免由于处理零碎变更而影响项目进度。针对会议结果可向客户正式提交一份需求变更计划,注明变更引起的时间、成本、工期代价和增加工作量等。要求客户配合需求变更计划,确定变更时限,控制变更规模,过时变更不候,离谱变更不做,保大局弃小变。

      (4)安排专职人员负责变更管理

      有时开发任务较重,开发人员容易陷入开发工作中而忽略了与客户的随时沟通。因此,需要安排一名专职的需求变更联络人员,负责与客户及时交流,跟踪和汇报需求变更完成进度和情况。同时,可以成立项目变更控制小组,负责裁定接受哪些变更,小组由项目所涉及的多方人员共同组成,应该包括客户方和开发方的决策人员在内。

      (5)确认客户是否接受变更的代价

      要让客户认识到变更都是有代价的,要和客户一起判断需求变更是否依然进行。例如,变更是没有问题的,但是要明确客户能否接受由此引起的如进度延迟、费用增加、效率下降等问题。一般来说,如果客户认为该变更是必须的(不是其上级领导拍脑袋提出的)就会接受这些后果。通过与客户协商,这样开发团队即使没有回报,也不会招致公司和客户双方的埋怨。

      如果客户认为该变更虽然有必要但是可以暂缓,双方签署备忘录后留待以后解决。如果客户认为该变更可有可无,多数情况下会取消变更。这样即可防止频繁变更,也让客户认识到不是所有的需求都需要变更。

  • 自动化测试实例:用QTP实现WEB页面链接扫描功能

    2010-07-09 17:00:56

    该函数实现用QTP脚本检查任何一个网页所有链接是否有效的功能。实际上,QTP自带一个对WEB page里的链接进行检查的checkpoint,但是不能自定义扩展和编辑;这里Sincky演示一个自定义的函数,模拟某个网页的每个链接发送HTTP请求、再检查HTTP响应结果来实现对该网页所有链接进行正确性扫描的过程。代码请见:

    '==========================================================================

    ' Name: CheckAllLinkReachable

    ' Summary: CheckAllLinkReachable

    ' Parameters:

    '         strBrowser: browser name

    '         strPage: page name

    '         strURLPattern: URL pattern you wan't to check. such as: ^http.*

    ' Return: None

    '==========================================================================

    Function CheckAllLinkReachable(strBrowser, strPage, strURLPattern)

            Dim blnReachable

             blnReachable = True

             Set bjXML = CreateObject("Msxml2.XMLHTTP")

            ' Get all link on the page

             Set bjDes = Description.Create

             objDes("micclass").Value = "Link"

             Set bjLinkList = Browser(strBrowser).Page(strPage).ChildObjects(objDes)

             For i = 0 To objLinkList.Count() - 1

                       ' Create XML HTTP Object

                       strURL = objLinkList(i).GetROProperty("href")

                       If RegExpTest(strURLPattern, strURL) Then

                                objXML.Open "POST", strURL, false

                                objXML.Send

                       '         msgbox objXML.responseText

                                print (objLinkList(i).GetROProperty("href") & " Ready State:" & objXML.readyState & " Status: " & objXML.status)

                                If objXML.status <> "200" Then

                                         blnReachable = False

                                End If

                                objXML.abort()            

                       End If

             Next

             Set bjXML = Nothing

             CheckAllLinkReachable = blnReachable

    End Function

  • linux文件系统基础知识

    2010-07-01 10:29:20

    这两天看了一本fedora 6的实践教程,下面是有关linux文件系统知识的学习笔记:
    1、linux文件系统分配策略:
        块分配( block allocation ) 和 扩展分配  ( extent allocation )
        块分配:磁盘上的文件块根据需要分配给文件,避免了存储空间的浪费。但当文件扩充时,会造成文件中文件块的不连续,从而导致过多的磁盘寻道时间。
                每一次文件扩展时,块分配算法就需要写入文件块的结构信息,也就是 meta-dada 。meta-data总是与文件一起写入存储设备,改变文件的操作要等到所有meta-data的操作都完成后才能进行,
                因此,meta-data的操作会明显降低整个文件系统的性能。
        扩展分配: 文件创建时,一次性分配一连串连续的块,当文件扩展时,也一次分配很多块。meta-data在文件创建时写入,当文件大小没有超过所有已分配文件块大小时,就不用写入meta-data,直到需要再分配文件块的时候。
                    扩展分配采用成组分配块的方式,减少了SCSI设备写数据的时间,在读取顺序文件时具有良好的性能,但随机读取文件时,就和块分配类似了。
                    文件块的组或块簇 ( block cluster) 的大小是在编译时确定的。簇的大小对文件系统的性能有很大的影响。
        注: meta-data 元信息:和文件有关的信息,比如权限、所有者以及创建、访问或更改时间等。
    2、文件的记录形式
        linux文家系统使用索引节点(inode)来记录文件信息。索引节点是一种数据结构,它包含了一个文件的长度、创建及修改时间、权限、所属关系、磁盘中的位置等信息。
    一个文件系统维护了一个索引节点的数组,每个文件或目录都与索引节点数组中的唯一的元素对应。每个索引节点在数组中的索引号,称为索引节点号。
        linux文件系统将文件索引节点号和文件名同时保存在目录中,所以,目录只是将文件的名称和它的索引节点号结合在一起的一张表,目录中每一对文件名称和索引节点号称为一个连接。
    对于一个文件来说,有一个索引节点号与之对应;而对于一个索引节点号,却可以对应多个文件名。
        连接分为软连接和硬连接,其中软连接又叫符号连接。
        硬连接: 原文件名和连接文件名都指向相同的物理地址。目录不能有硬连接;硬连接不能跨文件系统(不能跨越不同的分区),文件在磁盘中只有一个拷贝。
                由于删除文件要在同一个索引节点属于唯一的连接时才能成功,因此硬连接可以防止不必要的误删除。
        软连接: 用 ln -s 命令建立文件的符号连接。符号连接是linux特殊文件的一种,作为一个文件,它的数据是它所连接的文件的路径名。没有防止误删除的功能。
    3、文件系统类型:
       
        ext2 : 早期linux中常用的文件系统
        ext3 : ext2的升级版,带日志功能
        RAMFS : 内存文件系统,速度很快
        NFS : 网络文件系统,由SUN发明,主要用于远程文件共享
        MS-DOS : MS-DOS文件系统
        VFAT : Windows 95/98 操作系统采用的文件系统
        FAT : Windows XP 操作系统采用的文件系统
        NTFS : Windows NT/XP 操作系统采用的文件系统
        HPFS : OS/2 操作系统采用的文件系统
        PROC : 虚拟的进程文件系统
        ISO9660 : 大部分光盘所采用的文件系统
        ufsSun : OS 所采用的文件系统
        NCPFS : Novell 服务器所采用的文件系统
        SMBFS : Samba 的共享文件系统
        XFS : 由SGI开发的先进的日志文件系统,支持超大容量文件
        JFS :IBM的AIX使用的日志文件系统
        ReiserFS : 基于平衡树结构的文件系统
        udf: 可擦写的数据光盘文件系统
    4、虚拟文件系统VFS
       
        linux支持的所有文件系统称为逻辑文件系统,而linux在传统的逻辑文件系统的基础上增加料一个蓄念文件系统( Vitual File System ,VFS) 的接口层。
        虚拟文件系统(VFS) 位于文件系统的最上层,管理各种逻辑文件系统,并可以屏蔽各种逻辑文件系统之间的差异,提供统一文件和设备的访问接口。
    5、文件的逻辑结构
        文件的逻辑结构可分为两大类: 字节流式的无结构文件 和 记录式的有结构文件。
        由字节流(字节序列)组成的文件是一种无结构文件或流式文件 ,不考虑文件内部的逻辑结构,只是简单地看作是一系列字节的序列,便于在文件的任意位置添加内容。
        由记录组成的文件称为记录式文件 ,记录是这种文件类型的基本信息单位,记录式文件通用于信息管理。
    6、文件类型
       
        普通文件 : 通常是流式文件
        目录文件 : 用于表示和管理系统中的全部文件
        连接文件 : 用于不同目录下文件的共享
        设备文件 : 包括块设备文件和字符设备文件,块设备文件表示磁盘文件、光盘等,字符设备文件按照字符操作终端、键盘等设备。
        管道(FIFO)文件 :  提供进程建通信的一种方式
        套接字(socket) 文件: 该文件类型与网络通信有关
    7、文件结构: 包括索引节点和数据
        索引节点 : 又称 I 节点,在文件系统结构中,包含有关相应文件的信息的一个记录,这些信息包括文件权限、文件名、文件大小、存放位置、建立日期等。文件系统中所有文件的索引节点保存在索引节点表中。
        数据  : 文件的实际内容。可以是空的,也可以非常大,并且拥有自己的结构。
    8、ext2文件系统
       
        ext2文件系统的数据块大小一般为 1024B、2048B 或 4096B
        ext2文件系统采用的索引节点(inode):
            索引节点采用了多重索引结构,主要体现在直接指针和3个间接指针。直接指针包含12个直接指针块,它们直接指向包含文件数据的数据块,紧接在后面的3个间接指针是为了适应文件的大小变化而设计的。
        e.g: 假设数据块大小为1024B ,利用12个直接指针,可以保存最大为12KB的文件,当文件超过12KB时,则要利用单级间接指针,该指针指向的数据块保存有一组数据块指针,这些指针依次指向包含有实际数据的数据块,
            假如每个指针占用4B,则每个单级指针数据块可保存 1024/4=256 个数据指针,因此利用直接指针和单级间接指针可保存 1024*12+1024*256=268 KB的文件。当文件超过268KB时,再利用二级间接指针,直到使用三级间接指针。
            利用直接指针、单级间接指针、二级间接指针、三级间接指针可保存的最大文件大小为:
                1024*12+1024*256+1024*256*256+1024*256*256*256=16843020 KB,约 16GB
            若数据块大小为2048B,指针占4B,则最大文件大小为: 2048*12+2048*512+2048*512*512+2048*512*512*512=268,960,792 KB 约 268GB
            若数据块大小为4096B,指针占4B,则最大文件大小为: 4096*12+4096*1024+4096*1024*1024+4096*1024*1024*1024=4,299,165,744 KB ,约 4TB
        注: 命令 tune2fs -l /dev/sda5  可查看文件系统
        ext2文件系统最大文件名长度: 255个字符
       
        ext2文件系统的缺点:
                ext2在写入文件内容的同时并没有同时写入文件meta-data,    其工作顺序是先写入文件的内容,然后等空闲时候才写入文件的meta-data。若发生意外,则文件系统就会处于不一致状态。
            在重新启动系统的时候,linux会启动 fsk ( file system check) 的程序,扫描整个文件系统并试图修复,但不提供保证。
    9、ext3文件系统:
       
        ext3基于ext2的代码,所以磁盘格式与ext2相同,使用相同的元数据。
        ext2文件系统无损转化为ext3文件系统:  tune2fs  -j /dev/sda6
       
        日志块设备( Journaling block device layer,JBD)完成ext3文件系统日志功能。JBD不是ext3文件系统所特有的,它的设计目标是为了向一个块设备添加日志功能。
        当一个文件修改执行时,ext3文件系统代码将通知JBD,称为一个事务(transaction)。发生意外时,日志功能具有的重放功能,能重新执行中断的事务。
       
        日志中的3种数据模式:
            1)、data=writeback :不处理任何形式的日志数据,给用户整体上的最高性能
            2)、data=odered :只记录元数据日志,但将元数据和数据组成一个单元称为事务(transaction) 。此模式保持所句句的可靠性与文件系统的一致性,性能远低于data=writeback模式,但比data=journal模式快
            3)、data=journal :提供完整的数据及元数据日志,所有新数据首先被写入日志,然后才被定位。意外发生过后,日志可以被重放,将数据与元数据带回一致状态。这种模式整体性能最慢,但数据需要从磁盘读取和写入磁盘时却是3种模式中最快的。
        ext3文件系统最大文件名长度: 255个字符
        ext3文件系统的优点:可用性、数据完整性、速度、兼容性
    10、ReiserFS文件系统
       
        ReiserFS文件系统是由Hans Reiser和他领导的开发小组共同开发的,整个文件系统完全是从头设计的,是一个非常优秀的文件系统。也是最早用于Linux的日志文件系统之一。
        ReiserFS的特点
         先进的日志机制
            ReiserFS有先进的日志(Journaling/logging)功能 机制。日志机制保证了在每个实际数据修改之前,相应的日志已经写入硬盘。文件与数据的安全性有了很大提高。
         高效的磁盘空间利用
            Reiserfs对一些小文件不分配inode。而是将这些文件打包,存放在同一个磁盘分块中。而其它文件系统则为每个小文件分别放置到一个磁盘分块中。
         独特的搜寻方式
            ReiserFS基于快速平衡树(balanced tree)搜索,平衡树在性能上非常卓越,这是一种非常高效的算法。ReiserFS搜索大量文件时,搜索速度要比ext2快得多。Reiserfs文件系统使用B*Tree存储文件,而其它文件系统使用B+Tree树。B*Tree查询速度比B+Tree要快很多。Reiserfs在文件定位上速度非常快。
            在实际运用中,ReiserFS 在处理小于 4k 的文件时,比ext2 快 5 倍;带尾文件压缩功能(默认)的ReiserFS 比ext2文件系统多存储6%的数据。
        支持海量磁盘
            ReiserFS是一个非常优秀的文件系统,一直被用在高端UNIX系统上,可轻松管理上百G的文件系统,ReiserFS文件系统最大支持的文件系统尺寸为16TB。这非常适合企业级应用中。
        优异的性能
            由于它的高效存储和快速小文件I/O特点,使用ReiserFs文件系统的PC,在启动X窗口系统时,所花的时间要比在同一台机器上使用ext2文件系统少1/3。另外,ReiserFS文件系统支持单个文件尺寸为4G的文件,这为大型数据库系统在linux上的应用提供了更好的选择。
  • Linux内存使用

    2010-07-01 10:24:35

    一直对Linux的内存使用情况有一些困惑,主要是各个属性的内存量不是很理解,到底哪部分是属于正在使用的,那部分是系统缓存的。所以这次专门简单得了解了一下,虽然是一个很小的知识点,但是对于理解系统还有有一些好处的,所以记下来:
     
     
    free命令看一下内存使用状况:
     
    [root@prdmis-db /]# free
                 total       used       free     shared    buffers     cached
    Mem:       8175356     756824    7418532          0      94828     455868
    -/+ buffers/cache:     206128    7969228
    Swap:      2031608          0    2031608
     
     
     
    逐个解释一下这个表里的数据含义:
     
        1、Mem:表示对物理内存的使用情况统计
            * total:物理内存总量(即机器内存条的大小)
            * used:总共分配出去的内存量,包括实际使用和分给缓存(buffers or cache)
            * free:尚未分配的物理内存
            * shared:共享内存(普通系统都不会用到)
            * buffers:系统已分配,但尚未使用的buffers数量
            * cached:系统已分配,但尚未使用的cache数量
     
        2、-/+ buffers/cache:这个表示物理内存的缓存情况统计
            * used:实际使用的buffers与cache总量(即实际使用的内存总量)
            * free:未被使用的buffers与cache总量 加 未分配内存数 (即系统系统实际可用内存)
        3、Swap:表示硬盘上的交换分区使用情况
            * total:实际分配的交换分区大小
            * used:实际使用的交换分区大小
            * free:实际剩余的交换分区大小
     
     
    总结一下:
     
        1、 total1 = used1 + free1total1 = used2 + free2
        2、used1 = buffers1 + cached1 + used2
        3、free2 = buffers1 + cached1 + free1
        4、平时需要了解的,就是used2和free2
     
     
     
    关于buffer与cache的区别:

        A buffer is something that has yet to be "written" to disk.
        A cache is something that has been "read" from the disk and stored for later use.
  • linux命令助记表

    2010-06-29 17:15:40

    linux命令助记表
    命令    描述
    •    apropos whatis    显示和word相关的命令。 参见线程安全
    •    man -t man | ps2pdf - > man.pdf    生成一个PDF格式的帮助文件
         which command    显示命令的完整路径名
         time command    计算命令运行的时间
    •    time cat    开始计时. Ctrl-d停止。参见sw
    •    nice info    运行一个低优先级命令(这里是info)
    •    renice 19 -p $$    使脚本运行于低优先级。用于非交互任务。
    目录操作
    •    cd -    回到前一目录
    •    cd    回到用户目录
         (cd dir && command)    进入目录dir,执行命令command然后回到当前目录
    •    pushd .    将当前目录压入栈,以后你可以使用popd回到此目录
    文件搜索
    •    alias l='ls -l --color=auto'    单字符文件列表命令
    •    ls -lrt    按日期显示文件. 参见newest
    •    ls /usr/bin | pr -T9 -W$COLUMNS    在当前终端宽度上打印9列输出
         find -name '*.[ch]' | xargs grep -E 'expr'    在当前目录及其子目录下所有.c和.h文件中寻找'expr'. 参见findrepo
         find -type f -print0 | xargs -r0 grep -F 'example'    在当前目录及其子目录中的常规文件中查找字符串'example'
         find -maxdepth 1 -type f | xargs grep -F 'example'    在当前目录下查找字符串'example'
         find -maxdepth 1 -type d | while read dir; do echo $dir; echo cmd2; done    对每一个找到的文件执行多个命令(使用while循环)
    •    find -type f ! -perm -444    寻找所有不可读的文件(对网站有用)
    •    find -type d ! -perm -111    寻找不可访问的目录(对网站有用)
    •    locate -r 'file[^/]*\.txt'    使用locate 查找所有符合*file*.txt的文件
    •    look reference    在(有序)字典中快速查找
    •    grep --color reference /usr/share/dict/words    使字典中匹配的正则表达式高亮
    归档 and compression
         gpg -c file    文件加密
         gpg file.gpg    文件解密
         tar -c dir/ | bzip2 > dir.tar.bz2    将目录dir/压缩打包
         bzip2 -dc dir.tar.bz2 | tar -x    展开压缩包 (对tar.gz文件使用gzip而不是bzip2)
         tar -c dir/ | gzip | gpg -c | ssh user@remote 'dd f=dir.tar.gz.gpg'    目录dir/压缩打包并放到远程机器上
         find dir/ -name '*.txt' | tar -c --files-from=- | bzip2 > dir_txt.tar.bz2    将目录dir/及其子目录下所有.txt文件打包
         find dir/ -name '*.txt' | xargs cp -a --target-directory=dir_txt/ --parents    将目录dir/及其子目录下所有.txt按照目录结构拷贝到dir_txt/
         ( tar -c /dir/to/copy ) | ( cd /where/to/ && tar -x -p )    拷贝目录copy/到目录/where/to/并保持文件属性
         ( cd /dir/to/copy && tar -c . ) | ( cd /where/to/ && tar -x -p )    拷贝目录copy/下的所有文件到目录/where/to/并保持文件属性
         ( tar -c /dir/to/copy ) | ssh -C user@remote 'cd /where/to/ && tar -x -p'     拷贝目录copy/到远程目录/where/to/并保持文件属性
         dd bs=1M if=/dev/sda | gzip | ssh user@remote 'dd f=sda.gz'    将整个硬盘备份到远程机器上
    rsync (使用 --dry-run选项进行测试)
         rsync -P rsync://rsync.server.com/path/to/file file    只获取diffs.当下载有问题时可以作多次
         rsync --bwlimit=1000 fromfile tofile    有速度限制的本地拷贝,对I/O有利
         rsync -az -e ssh --delete ~/public_html/ remote.com:'~/public_html'    镜像网站(使用压缩和加密)
         rsync -auz -e ssh remote:/dir/ . && rsync -auz -e ssh . remote:/dir/    同步当前目录和远程目录
    ssh (安全 Shell)
         ssh $USER@$HOST command    在$Host主机上以$User用户运行命令(默认命令为Shell)
    •    ssh -f -Y $USER@$HOSTNAME xeyes    在名为$HOSTNAME的主机上以$USER用户运行GUI命令
         scp -p -r $USER@$HOST: file dir/    拷贝到$HOST主机$USER'用户的目录下
         ssh -g -L 8080:localhost:80 root@$HOST    由本地主机的8080端口转发到$HOST主机的80端口
         ssh -R 1434:imap:143 root@$HOST    由主机的1434端口转发到imap的143端口
    wget (多用途下载工具)
    •    (cd cmdline && wget -nd -pHEKk http://www.pixelbeat.org/cmdline.html)    在当前目录中下载指定网页及其相关的文件使其可完全浏览
         wget -c http://www.example.com/large.file    继续上次未完的下载
         wget -r -nd -np -l1 -A '*.jpg' http://www.example.com/    批量下载文件到当前目录中
         wget ftp://remote/file[1-9].iso/    下载FTP站上的整个目录
    •    wget -q -O- http://www.pixelbeat.org/timeline.html | grep 'a href' | head    直接处理输出
         echo 'wget url' | at 01:00    在下午一点钟下载指定文件到当前目录
         wget --limit-rate=20k url    限制下载速度(这里限制到20KB/s)
         wget -nv --spider --force-html -i bookmarks.html    检查文件中的链接是否存在
         wget --mirror http://www.example.com/    更新网站的本地拷贝(可以方便地用于cron)
    网络(ifconfig, route, mii-tool, nslookup 命令皆已过时)
         ethtool eth0    显示网卡eth0的状态
         ethtool --change eth0 autoneg off speed 100 duplex full    手动设制网卡速度
         iwconfig eth1    显示无线网卡eth1的状态
         iwconfig eth1 rate 1Mb/s fixed    手动设制无线网卡速度
    •    iwlist scan    显示无线网络列表
    •    ip link show    显示interface列表
         ip link set dev eth0 name wan    重命名eth0为wan
         ip link set dev eth0 up    启动interface eth0(或关闭)
    •    ip addr show    显示网卡的IP地址
         ip addr add 1.2.3.4/24 brd + dev eth0    添加ip和掩码(255.255.255.0)
    •    ip route show    显示路由列表
         ip route add default via 1.2.3.254    设置默认网关1.2.3.254
    •    tc qdisc add dev lo root handle 1:0 netem delay 20msec    增加20ms传输时间到loopback设备(调试用)
    •    tc qdisc del dev lo root    移除上面添加的传输时间
    •    host pixelbeat.org    查寻主机的DNS IP地址
    •    hostname -i    查寻本地主机的IP地址(同等于host `hostname`)
    •    whois pixelbeat.org    查寻某主机或莫IP地址的whois信息
    •    netstat -tupl    列出系统中的internet服务
    •    netstat -tup    列出活跃的连接
    windows networking (samba提供所有windows相关的网络支持)
    •    smbtree    寻找一个windows主机. 参见findsmb
         nmblookup -A 1.2.3.4    寻找一个指定ip的windows (netbios)名
         smbclient -L windows_box    显示在windows主机或samba服务器上的所有共享
         mount -t smbfs -o fmask=666,guest //windows_box/share /mnt/share    挂载一个windows共享
         echo 'message' | smbclient -M windows_box    发送一个弹出信息到windows主机(XP sp2默认关闭此功能)
    文本操作 (sed使用标准输入和标准输出,如果想要编辑文件,则需添加<oldfile >newfile)
         sed 's/string1/string2/g'    使用string2替换string1
         sed 's/\(.*\)1/\12/g'    将任何以1结尾的字符串替换为以2结尾的字符串
         sed '/ *#/d; /^ *$/d'    删除注释和空白行
         sed ':a; /\\$/N; s/\\\n//; ta'    连接结尾有\的行和其下一行
         sed 's/[ \t]*$//'    删除每行后的空白
         sed 's/\([\\`\\"$\\\\]\)/\\\1/g'    将所有转义字符之前加上\
    •    seq 10 | sed "s/^/      /; s/ *\(.\{7,\}\)/\1/"    向右排N(任意数)列
         sed -n '1000p;1000q'    输出第一千行
         sed -n '10,20p;20q'    输出第10-20行
         sed -n 's/.*<title>\(.*\)<\/title>.*/\1/ip;T;q'    输出HTML文件的<title></title>字段中的 内容
         sort -t. -k1,1n -k2,2n -k3,3n -k4,4n    排序IPV4地址
    •    echo 'Test' | tr '[:lower:]' '[:upper:]'    转换成大写
    •    tr -dc '[:print:]' < /dev/urandom    过滤掉不能打印的字符
    •    history | wc -l    计算指定单词出现的次数
    集合操作 (如果是英文文本的话export LANG=C可以提高速度)
         sort file1 file2 | uniq    两个未排序文件的并集
         sort file1 file2 | uniq -d    两个未排序文件的交集
         sort file1 file1 file2 | uniq -u    两个未排序文件的差 集
         sort file1 file2 | uniq -u    两个未排序文件的对称差集
         join -t'\0' -a1 -a2 file1 file2    两个有序文件的并集
         join -t'\0' file1 file2    两个有序文件的交集
         join -t'\0' -v2 file1 file2    两个有序文件的差集
         join -t'\0' -v1 -v2 file1 file2    两个有序文件的对称差集
    数学
    •    echo '(1 + sqrt(5))/2' | bc -l    方便的计算器(计算 φ)
    •    echo 'pad=20; min=64; (100*10^6)/((pad+min)*8)' | bc    更复杂地计算,这里计算了最大的FastE包率
    •    echo 'pad=20; min=64; print (100E6)/((pad+min)*8)' | python    Python处理数值的科学表示法
    •    echo 'pad=20; plot [64:1518] (100*10**6)/((pad+x)*8)' | gnuplot -persist    显示FastE包率相对于包大小的图形
    •    echo 'obase=16; ibase=10; 64206' | bc    进制转换(十进制到十六进制)
    •    echo $((0x2dec))    进制转换(十六进制到十进制)((shell数学扩展))
    •    units -t '100m/9.58s' 'miles/hour'    单位转换(公尺到英尺)
    •    units -t '500GB' 'GiB'    单位转换(SI 到IEC 前缀)
    •    units -t '1 googol'    定义查找
    •    seq 100 | (tr '\n' +; echo 0) | bc    加N(任意数)列. 参见 add and funcpy
    日历
    •    cal -3    显示一日历
    •    cal 9 1752    显示指定月,年的日历
    •    date -d fri    这个星期五是几号. 参见day
    •    date --date='25 Dec' +%A    今年的圣诞节是星期几
    •    date --date '1970-01-01 UTC 2147483647 seconds'    将一相对于1970-01-01 00:00的秒数转换成时间
    •    TZ=':America/Los_Angeles' date    显示当前的美国西岸时间(使用tzselect寻找时区)
         echo "mail -s 'get the train' P@draigBrady.com < /dev/null" | at 17:45    在指定的时间发送邮件
    •    echo "DISPLAY=$DISPLAY xmessage cooker" | at "NOW + 30 minutes"    在给定的时间弹出对话框
    locales
    •    printf "%'d\n" 1234    根据locale输出正确的数字分隔
    •    BLOCK_SIZE=\'1 ls -l    用ls命令作类适于locale()文件分组
    •    echo "I live in `locale territory`"    从locale数据库中展开信息
    •    LANG=en_IE.utf8 locale int_prefix    查找指定地区的locale信息。参见ccodes
    •    locale | cut -d= -f1 | xargs locale -kc | less    显示在locale数据库中的所有字段
    recode (iconv, dos2unix, unix2dos 已经过时了)
    •    recode -l | less    显示所有有效的字符集及其别名
         recode windows-1252.. file_to_change.txt    转换Windows下的ansi文件到当前的字符集(自动进行回车换行符的转换)
         recode utf-8/CRLF.. file_to_change.txt    转换Windows下的ansi文件到当前的字符集
         recode iso-8859-15..utf8 file_to_change.txt    转换Latin9(西欧)字符集文件到utf8
         recode ../b64 < file.txt > file.b64    Base64编码
         recode /qp.. < file.txt > file.qp    Quoted-printable格式解码
         recode ..HTML < file.txt > file.html    将文本文件转换成HTML
    •    recode -lf windows-1252 | grep euro    在字符表中查找欧元符号
    •    echo -n 0x80 | recode latin-9/x1..dump    显示字符在latin-9中的字符映射
    •    echo -n 0x20AC | recode ucs-2/x2..latin-9/x    显示latin-9编码
    •    echo -n 0x20AC | recode ucs-2/x2..utf-8/x    显示utf-8编码
    光盘
         gzip < /dev/cdrom > cdrom.iso.gz    保存光盘拷贝
         mkisofs -V LABEL -r dir | gzip > cdrom.iso.gz    建立目录dir的光盘镜像
         mount -o loop cdrom.iso /mnt/dir    将光盘镜像挂载到 /mnt/dir (只读)
         cdrecord -v dev=/dev/cdrom blank=fast    清空一张CDRW
         gzip -dc cdrom.iso.gz | cdrecord -v dev=/dev/cdrom -    烧录光盘镜像 (使用 dev=ATAPI -scanbus 来确认该使用的 dev)
         cdparanoia -B    在当前目录下将光盘音轨转录成wav文件
         cdrecord -v dev=/dev/cdrom -audio *.wav    将当前目录下的wav文件烧成音乐光盘 (参见cdrdao)
         oggenc --tracknum='track' track.cdda.wav -o 'track.ogg'    将wav文件转换成ogg格式
    磁盘空间 (参见FSlint)
    •    ls -lSr    按文件大小降序显示文件
    •    du -s * | sort -k1,1rn | head    显示当前目录下占用空间最大的一批文件. 参见dutop
    •    df -h    显示空余的磁盘空间
    •    df -i    显示空余的inode
    •    fdisk -l    显示磁盘分区大小和类型(在root下执行)
    •    rpm -q -a --qf '%10{SIZE}\t%{NAME}\n' | sort -k1,1n    显示所有在rpm发布版上安装的包,并以包字节大小为序
    •    dpkg-query -W -f='${Installed-Size;10}\t${Package}\n' | sort -k1,1n    显示所有在deb发布版上安装的包,并以KB包大小为序
    •    dd bs=1 seek=2TB if=/dev/null f=ext3.test    建立一个大的测试文件(不占用空间). 参见truncate
    监视/调试
    •    tail -f /var/log/messages    监视Messages日志文件
    •    strace -c ls >/dev/null    总结/剖析命令进行的系统调用
    •    strace -f -e open ls >/dev/null    显示命令进行的系统调用
    •    ltrace -f -e getenv ls >/dev/null    显示命令调用的库函数
    •    lsof -p $$    显示当前进程打开的文件
    •    lsof ~    显示打开用户目录的进程
    •    tcpdump not port 22    显示除了ssh外的网络交通. 参见tcpdump_not_me
    •    ps -e -o pid,args --forest    以树状结构显示进程
    •    ps -e -o pcpu,cpu,nice,state,cputime,args --sort pcpu | sed '/^ 0.0 /d'    以CPU占用率为序显示进程
    •    ps -e -orss=,args= | sort -b -k1,1n | pr -TW$COLUMNS    以内存使用量为序显示进程. 参见ps_mem.py
    •    ps -C firefox-bin -L -o pid,tid,pcpu,state    显示指定进程的所有线程信息
    •    ps -p 1,2    显示指定进程ID的进程信息
    •    last reboot    显示系统重启记录
    •    free -m    显示(剩余的)内存总量(-m以MB为单位显示)
    •    watch -n.1 'cat /proc/interrupts'    监测文件/proc/interrupts的变化
    系统信息 (参见sysinfo)
    •    uname -a    查看内核/操作系统/CPU信息
    •    head -n1 /etc/issue    查看操作系统版本
    •    cat /proc/partitions    显示所有在系统中注册的分区
    •    grep MemTotal /proc/meminfo    显示系统可见的内存总量
    •    grep "model name" /proc/cpuinfo    显示CPU信息
    •    lspci -tv    显示PCI信息
    •    lsusb -tv    显示USB信息
    •    mount | column -t    显示所有挂载的文件系统并对齐输出
    #    dmidecode -q | less    显示SMBIOS/DMI 信息
    #    smartctl -A /dev/sda | grep Power_On_Hours    系统开机的总体时间
    #    hdparm -i /dev/sda    显示关于磁盘sda的信息
    #    hdparm -tT /dev/sda    检测磁盘sda的读取速度
    #    badblocks -s /dev/sda    检测磁盘sda上所有的坏扇区
    交互 (参见linux keyboard shortcut database)
    •    readline    Line editor used by bash, python, bc, gnuplot, ...
    •    screen    多窗口的虚拟终端, ...
    •    mc    强大的文件管理器,可以浏览rpm, tar, ftp, ssh, ...
    •    gnuplot    交互式并可进行脚本编程的画图工具
    •    links    网页浏览器
    miscellaneous
    •    alias hd='od -Ax -tx1z -v'    方便的十六进制输出。 (用法举例: • hd /proc/self/cmdline | less)
    •    alias realpath='readlink -f'    显示符号链接指向的真实路径((用法举例: • realpath ~/../$USER)
    •    set | grep $USER    在当前环境中查找
         touch -c -t 0304050607 file    改变文件的时间标签 (YYMMDDhhmm)
    •    python -m SimpleHTTPServer    Serve current directory tree at http://$HOSTNAME:8000/
  • top查看进程占用内存

    2010-06-29 17:07:44

    如何监控linux下的进程占用内存的情况

    top -d 1

    然后shift + m(Sort by memory usage)
  • Web安全测试学习笔记(Cookie&Session)

    2009-05-30 23:03:59

     

    一,Session:含义:有始有终的一系列动作\消息
    1, 隐含了“面向连接”
    和“保持状态”两种含义
    2,
    一种用来在客户端与服务器之间保持状态的解决方案
    3, 也指这种解决方案的存储结构“把××保存在session里”

    二, http 协议本来是无状态的,所以引进了cookiesession机制来保持连接状态

    cookiesession 机制之间的区别与联系:
    cookie
    机制采用的是在客户端保持状态的方法
    session机制采用的是在服务器端保持状态的方案,由于在服务器端保 持状态的同时必须要求客户端提供一个标识,

    三,关于cookie机制
    Cookie 的使用是由浏览器按照一定的原则在后台自动发送给服务器的,浏览器会检查所有存储的cookie,如果某个cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该cookie附在请求资源的http请求头上发送给服务器。
    存储在硬盘上的cookie可以在不同的浏览器进程间共享,比如两个IE窗口。而保存在内存里的cookie,不同的浏览器有不同的处理方式,对于IE,在一个打开的窗口上按CTRL N(从文件菜单)打开的窗口可以与原窗口共享cookie,而使用其他方式新开的IE进程则不能共享已经打开的窗口的内存cookie

    Cookie的内容包括: 名字,值,过期时间,路径和域

    四,关于session的机制
        当程序需要为某个客户端的请求创建一个session的时候,服务器首先检查这个请求是否含了一个session 标识(session id),如果有,则说明以前为该客户创建了一个session,服务器就按照session id把这个session检索出来用,一般一个cookie的名字就是类似于session ID,如果cookie被禁止的时候(cookie可以被人为的禁止),经常使用重写URL的方式,把session ID附加在URL路径后面,为了在整个交互过程中始终保持状态,就必须在每个客户端可能请求的路径后面都包含这个session id
        人们以为:“把浏览器关闭了,session 就小时了”其实不对,除非程序通知服务器删除一个session,否则服务器会一直保留,而程序一般都是在用户作log off的时候发个指令去删除session。人们之所以会产生这种错觉,是因为大部分session会采用cookie来保存session,而关闭浏览器后这个session就消失了,如果服务器设置的cookie被保存到硬盘上,或者使用某种手段改写浏览器发出的http请求头,把原来的session id发送给服务器,则再次打开浏览器,其实是可以再次找到之前的session id的。所以设置失效时间可以起到一定的保护作用。

    五,关于session的一些问题
    1, session何时被创建: 不是在客户端访问时就被创建,而是在服务器端调用httpservletRequest.getSession(true)时才被创建。
    2, session何时被删除: A,程序调用httpSession.invalidate(),B距离上一次收到客户端发送的session id时间间隔超过了session的超时设置 C 服务器进程被停止(非持久session

    3, 如何做到关闭浏览器同时关闭session 严格说做不到,可以让所有的客户端页面使用window.onclose来监视浏览器的关闭东西,然后向服务器发送一个请求来删除session,但是对于浏览器崩溃或者强行杀死进程时仍然无能为力。

  • LoadRunner英文 面试问题(附答案)

    2009-05-22 16:40:56

    1.     What is load testing? - Load testing is to test that if the application works fine with the loads that result from large number of simultaneous users, transactions and to determine weather it can handle peak usage periods.

    2.     What is Performance testing? - Timing for both read and update transactions should be gathered to determine whether system functions are being performed in an acceptable timeframe. This should be done standalone and then in a multi user environment to determine the effect of multiple transactions on the timing of a single transaction.

    3.     Did u use LoadRunner? What version? - Yes. Version 7.2.

    4.     Explain the Load testing process? -
    Step 1: Planning the test. Here, we develop a clearly defined test plan to ensure the test scenarios we develop will accomplish load-testing objectives. Step 2: Creating Vusers. Here, we create Vuser scrīpts that contain tasks performed by each Vuser, tasks performed by Vusers as a whole, and tasks measured as transactions. Step 3: Creating the scenario. A scenario describes the events that occur during a testing session. It includes a list of machines, scrīpts, and Vusers that run during the scenario. We create scenarios using LoadRunner Controller. We can create manual scenarios as well as goal-oriented scenarios. In manual scenarios, we define the number of Vusers, the load generator machines, and percentage of Vusers to be assigned to each scrīpt. For web tests, we may create a goal-oriented scenario where we define the goal that our test has to achieve. LoadRunner automatically builds a scenario for us. Step 4: Running the scenario.
    We emulate load on the server by instructing multiple Vusers to perform. tasks simultaneously. Before the testing, we set the scenario configuration and scheduling. We can run the entire scenario, Vuser groups, or individual Vusers. Step 5: Monitoring the scenario.
    We monitor scenario execution using the LoadRunner online runtime, transaction, system resource, Web resource, Web server resource, Web application server resource, database server resource, network delay, streaming media resource, firewall server resource, ERP server resource, and
    Java performance monitors. Step 6: Analyzing test results. During scenario execution, LoadRunner records the performance of the application under different loads. We use LoadRunner’s graphs and reports to analyze the application’s performance.

    5.     When do you do load and performance Testing? - We perform. load testing once we are done with interface (GUI) testing. Modern system architectures are large and complex. Whereas single user testing primarily on functionality and user interface of a system component, application testing focuses on performance and reliability of an entire system. For example, a typical application-testing scenario might depict 1000 users logging in simultaneously to a system. This gives rise to issues such as what is the response time of the system, does it crash, will it go with different software applications and platforms, can it hold so many hundreds and thousands of users, etc. This is when we set do load and performance testing.

    6.     What are the components of LoadRunner? - The components of LoadRunner are The Virtual User Generator, Controller, and the Agent process, LoadRunner Analysis and Monitoring, LoadRunner Books Online.

    7.     What Component of LoadRunner would you use to record a scrīpt? - The Virtual User Generator (VuGen) component is used to record a scrīpt. It enables you to develop Vuser scrīpts for a variety of application types and communication protocols.

    8.     What Component of LoadRunner would you use to play Back the scrīpt in multi user mode? - The Controller component is used to playback the scrīpt in multi-user mode. This is done during a scenario run where a vuser scrīpt is executed by a number of vusers in a group.

    9.     What is a rendezvous point? - You insert rendezvous points into Vuser scrīpts to emulate heavy user load on the server. Rendezvous points instruct Vusers to wait during test execution for multiple Vusers to arrive at a certain point, in order that they may simultaneously perform. a task. For example, to emulate peak load on the bank server, you can insert a rendezvous point instructing 100 Vusers to deposit cash into their accounts at the same time.

    10. What is a scenario? - A scenario defines the events that occur during each testing session. For example, a scenario defines and controls the number of users to emulate, the actions to be performed, and the machines on which the virtual users run their emulations.

    11. Explain the recording mode for web Vuser scrīpt? - We use VuGen to develop a Vuser scrīpt by recording a user performing typical business processes on a client application. VuGen creates the scrīpt by recording the activity between the client and the server. For example, in web based applications, VuGen monitors the client end of the database and traces all the requests sent to, and received from, the database server. We use VuGen to: Monitor the communication between the application and the server; Generate the required function calls; and Insert the generated function calls into a Vuser scrīpt.

    12. Why do you create parameters? - Parameters are like scrīpt variables. They are used to vary input to the server and to emulate real users. Different sets of data are sent to the server each time the scrīpt is run. Better simulate the usage model for more accurate testing from the Controller; one scrīpt can emulate many different users on the system.

    13. What is correlation? Explain the difference between automatic correlation and manual correlation? - Correlation is used to obtain data which are unique for each run of the scrīpt and which are generated by nested queries. Correlation provides the value to avoid errors arising out of duplicate values and also optimizing the code (to avoid nested queries). Automatic correlation is where we set some rules for correlation. It can be application server specific. Here values are replaced by data which are created by these rules. In manual correlation, the value we want to correlate is scanned and create correlation is used to correlate.

    14. How do you find out where correlation is required? Give few examples from your projects? - Two ways: First we can scan for correlations, and see the list of values which can be correlated. From this we can pick a value to be correlated. Secondly, we can record two scrīpts and compare them. We can look up the difference file to see for the values which needed to be correlated.  In my project, there was a unique id developed for each customer, it was nothing but Insurance Number, it was generated automatically and it was sequential and this value was unique. I had to correlate this value, in order to avoid errors while running my scrīpt. I did using scan for correlation.

    15. Where do you set automatic correlation options? - Automatic correlation from web point of view can be set in recording options and correlation tab. Here we can enable correlation for the entire scrīpt and choose either issue online messages or offline actions, where we can define rules for that correlation. Automatic correlation for database can be done using show output window and scan for correlation and picking the correlate query tab and choose which query value we want to correlate. If we know the specific value to be correlated, we just do create correlation for the value and specify how the value to be created.

    16. What is a function to capture dynamic values in the web Vuser scrīpt? - Web_reg_save_param function saves dynamic data information to a parameter.

    17. When do you disable log in Virtual User Generator, When do you choose standard and extended logs? - Once we debug our scrīpt and verify that it is functional, we can enable logging for errors only. When we add a scrīpt to a scenario, logging is automatically disabled. Standard Log Option: When you select
    Standard log, it creates a standard log of functions and messages sent during scrīpt execution to use for debugging. Disable this option for large load testing scenarios. When you copy a scrīpt to a scenario, logging is automatically disabled Extended Log Option: Select
    extended log to create an extended log, including warnings and other messages. Disable this option for large load testing scenarios. When you copy a scrīpt to a scenario, logging is automatically disabled. We can specify which additional information should be added to the extended log using the Extended log options.

    18. How do you debug a LoadRunner scrīpt? - VuGen contains two options to help debug Vuser scrīpts-the Run Step by Step command and breakpoints. The Debug settings in the Options dialog box allow us to determine the extent of the trace to be performed during scenario execution. The debug information is written to the Output window. We can manually set the message class within your scrīpt using the lr_set_debug_message function. This is useful if we want to receive debug information about a small section of the scrīpt only.

    19. How do you write user defined functions in LR? Give me few functions you wrote in your previous project? - Before we create the User Defined functions we need to create the external
    library (DLL) with the function. We add this library to VuGen bin directory. Once the library is added then we assign user defined function as a parameter. The function should have the following format: __declspec (dllexport) char* <function name>(char*, char*)Examples of user defined functions are as follows:GetVersion, GetCurrentTime, GetPltform. are some of the user defined functions used in my earlier project.

    20. What are the changes you can make in run-time settings? - The Run Time Settings that we make are: a) Pacing - It has iteration count. b) Log - Under this we have Disable Logging Standard Log and c) Extended Think Time - In think time we have two options like Ignore think time and Replay think time. d) General - Under general tab we can set the vusers as process or as multithreading and whether each step as a transaction.

    21. Where do you set Iteration for Vuser testing? - We set Iterations in the Run Time Settings of the VuGen. The navigation for this is Run time settings, Pacing tab, set number of iterations.

    22. How do you perform. functional testing under load? - Functionality under load can be tested by running several Vusers concurrently. By increasing the amount of Vusers, we can determine how much load the server can sustain.

    23. What is Ramp up? How do you set this? - This option is used to gradually increase the amount of Vusers/load on the server. An initial value is set and a value to wait between intervals can be
    specified. To set Ramp Up, go to ‘Scenario Scheduling Options’

    24. What is the advantage of running the Vuser as thread? - VuGen provides the facility to use multithreading. This enables more Vusers to be run per
    generator. If the Vuser is run as a process, the same driver program is loaded into memory for each Vuser, thus taking up a large amount of memory. This limits the number of Vusers that can be run on a single
    generator. If the Vuser is run as a thread, only one instance of the driver program is loaded into memory for the given number of
    Vusers (say 100). Each thread shares the memory of the parent driver program, thus enabling more Vusers to be run per generator.

    25. If you want to stop the execution of your scrīpt on error, how do you do that? - The lr_abort function aborts the execution of a Vuser scrīpt. It instructs the Vuser to stop executing the Actions section, execute the vuser_end section and end the execution. This function is useful when you need to manually abort a scrīpt execution as a result of a specific error condition. When you end a scrīpt using this function, the Vuser is assigned the status "Stopped". For this to take effect, we have to first uncheck the “Continue on error” option in Run-Time Settings.  

    26. What is the relation between Response Time and Throughput? - The Throughput graph shows the amount of data in bytes that the Vusers received from the server in a second. When we compare this with the transaction response time, we will notice that as throughput decreased, the response time also decreased. Similarly, the peak throughput and highest response time would occur approximately at the same time.

    27. Explain the Configuration of your systems? - The configuration of our systems refers to that of the client machines on which we run the Vusers. The configuration of any client machine includes its hardware settings, memory, operating system, software applications, development tools, etc. This system component configuration should match with the overall system configuration that would include the network infrastructure, the web server, the database server, and any other components that go with this larger system so as to achieve the load testing objectives.

    28. How do you identify the performance bottlenecks? - Performance Bottlenecks can be detected by using monitors. These monitors might be application server monitors, web server monitors, database server monitors and network monitors. They help in finding out the troubled area in our scenario which causes increased response time. The measurements made are usually performance response time, throughput, hits/sec, network delay graphs, etc.

    29. If web server, database and Network are all fine where could be the problem? - The problem could be in the system itself or in the application server or in the code written for the application.

    30. How did you find web server related issues? - Using Web resource monitors we can find the performance of web servers. Using these monitors we can analyze throughput on the web server, number of hits per second that
    occurred during scenario, the number of http responses per second, the number of downloaded pages per second.

    31. How did you find database related issues? - By running “Database” monitor and help of “Data Resource Graph” we can find database related issues. E.g. You can specify the resource you want to measure on before running the controller and than you can see database related issues

    32. Explain all the web recording options?

    33. What is the difference between Overlay graph and Correlate graph? - Overlay Graph: It overlay the content of two graphs that shares a common x-axis. Left Y-axis on the merged graph show’s the current graph’s value & Right Y-axis show the value of Y-axis of the graph that was merged. Correlate Graph: Plot the Y-axis of two graphs against each other. The active graph’s Y-axis becomes X-axis of merged graph. Y-axis of the graph that was merged becomes merged graph’s Y-axis.

    34. How did you plan the Load? What are the Criteria? - Load test is planned to decide the number of users, what kind of machines we are going to use and from where they are run. It is based on 2 important documents, Task Distribution Diagram and Transaction profile. Task Distribution Diagram gives us the information on number of users for a particular transaction and the time of the load. The peak usage and off-usage are decided from this Diagram. Transaction profile gives us the information about the transactions name and their priority levels with regard to the scenario we are deciding.

    35. What does vuser_init action contain? - Vuser_init action contains procedures to login to a server.

    36. What does vuser_end action contain? - Vuser_end section contains log off procedures.  

    查看(199) 评论(1) 收藏 分享 管理

  • LoadRunner 概念和参数(转)

    2009-05-21 17:24:33

    事务TRANSACTION

    所谓事务(TRANSACTION),就是在脚本定义中定义的某段操作(ACTION),更确切的说,就是一段脚本语句.定义事务时,首先在脚本中找到事务的开始和结束位置,然后分别插入一个事务起始标记,这样,当脚本运行的时候,LOADRUNER会自动在事务的起始点计时,脚本在运行到事务结束点时计时结束,系统会自动记录这段操作的运行时间等性能数据;在脚本运行完毕后,系统会在结果信息中单独反映每个事务运行结果.

    LR_START_TRANSACTION(“事务名称”)

    LR_END_TRANSACTION(“事务名称“)

    集合点RENDEZVOUS

    多用户同时加载并发,并发过程仅仅体现在开始执行的那一刹那,随着服务器对请求的响应时间的不一致或系统环境条件的限制,在运行过程中能集合到一点的可能性微乎其微,所以将一定数量的用户同时加载并不是真正意义上的并发.

    系统压力最大的情况是:所有用户都集中到系统瓶颈的某个点上进行操作,从脚本的角度来讲,这个点就是执行脚本的某一条或一段语句,为了真实模拟这个最坏的情况,查看系统在最坏情况下的反映,LOADRUNNER提供了集合点的功能,帮助测试人员实现真正意义上的并发.

    LR_RENDEZVOUS(“集合点名称”)

    参数化PARAMETERS

    让所有用户都使用相同的数据来运行,对系统造成的压力与实际情况会有所不同.而对于那些禁止一个用户多次登陆的系统,也就严重到无法测试的地步了.为了解决这个问题,让系统更加真实的模拟多用户使用的实际环境,LOADRUNNER提供了对脚本进行参数化输入的功能.

    所谓的脚本参数化,就是针对脚本中的某些常量,定义一个或多个包含数据源的参数来取代,让场景中不同的虚拟用户在执行相同的脚本时,分别使用参数数据源中的不同数据代替这些常量,从而达到模拟多用户真实使用系统的目的.

    注:参数化输入只能用于函数中的参数,不能用参数代替非函数中的常量参数.

    检查点CHECKPOINT

    LOADRUNNER检查点的功能主要用来验证某个界面上是否存在指定的TEXT或IMAGE等对象,在使用LOADRUNNER测试WEB应用时,可以检查压力较大时WEB服务器能否返回正常的页面。

    系统在执行时是否起用检查点,是由一个系统参数控制的,该参数的设定方法为:VUSER|RUN-TIME SETTINGS|PREFERENCES,如果想让检查点起作用,需要选中ENABLE IMAGE AND TEXT CHECK 复选框。

    Ø RUN-TIME SETTINGS

    ITERATION COUNT(重复次数)

    入口:GENERAL|RUN LOGIC;

    参数说明:设定每个ACTION的重复执行次数;

    注意:DURATION参数是优先于ITERATION的,举例说明,假定将DURATION设为5分钟,即使在RUN-TIME中将INRATIONS参数设为1,虚拟用户也会在5分钟之内进行尽可能多的反复执行脚本,在限定了DURATION的场景中,DURATION时间是从所有用户状态变为INIT开始计算的,这样就存在一个问题,有些初始化过程很长的用户,可能还没有到达RUN状态就因DURATION时间限制而中止了,要解决这个问题,测试人员可选择INITIALIZE ALL VUSERS BEFORE RUN选项,这样DURATION时间会在所有用户都到达RUN状态后开始计时.

    THINK TIME

    参数设定入口:GENERAL|THINK TIME

    参数说明:设定脚本回放时对思考时间的处理方式.

    IGNORE THINK TIME:

    选择该选项,脚本回放时将不在执行LR_THINK_TIME()函数,这样会给服务器造成更大的压力.

    REPLAY THINK TIME:

    选择该选项,脚本回放时执行LR_THINK_TIME()函数,

    ERROR HANDLING

    入口:GENERAL|MISCELLANEOUS

    参数说明:设定遇到错误时的处理方式

    1,CONTINUE ON ERROR,遇到错误继续运行;

    2,FAIL OPEN TRANSACTIONS ON LR_ERROR_MESSAGE,

    执行到事务中调用的LR_ERROR_MESSAGE()函数时将事务的结果置为FAILED

    3,GENERATE SNAJPSHOT ON ERROR对错误进行快照.

    MULTITHREADING

    设定脚本运行方式;

    入口:GENERATOR|MISCELLANEOUS

    1,RUN VUSER AS A PROCESS,以多进程方式运行;

    2,RUN VUSER AS A THREAD,以多线程方式运行;

    关联Correlation

    Ø 自动关联---- Rules Correlation

    1. 启用auto-correlation

    点选VuGen的【Tools】>【Recording Options】,开启【Recording Options】对话窗口,选取【Internet Protocol】>【Correlation】,勾选【Enable correlation during recording】,以启用自动关联。

    设定当VuGen侦测到符合关联规则的数据时,要如何处理:

    【Issue a pop-up message and let me decide online】:跳出一个讯息对话窗口,询问您是否要建立关联。

    【Perform. correlation in sceipt】:直接自动建立关联

    Ø 自动关联----Correlation Studio

    使用Correlation Studio的步骤如下:

    1. 录制脚本并执行;

    2. 执行完毕后,VuGen会跳出下面的【Scan Action for Correlation】窗口,询问您是否要扫描脚本并建立关联,按下【Yes】按钮。

    3. 扫描完后,可以在脚本下方的【Correlation Results】中看到扫描的结果。

    4. 检查一下扫瞄的结果后,选择要做关联的数据,然后按下【Correlate】按钮,一笔一笔做,或是按下【Correlate All】让VuGen一次就对所有的数据建立关联。
    注意:由于Correlation Studio会找出所有有变动的数据,但是并不是所有的数据都需要做关联,所以不建议您直接用【Correlate All】。

    Ø 手动关联

    有可能有些需要做关联的动态数据,连Correlation Studio都无法侦测出来,这时您就需要自行做手动关联了。

    CONTROLLER场景

    Ø MANUAL SCENARIO这种方式是完全手动设置,测试人员需要手工设定虚拟用户数,SCHEDULE和LOADGENERATOR等

    Ø MANUAL SCENARI WITH PERCENTAGE MODE 这种方式与MAMUAL SCENARIO方式比较相似,只是在分配用户数的方式有所不同

    1,后者需要设定TOTAL NUMBER OF VUSERS,即所有虚拟用户数;

    2,后者需要为每个脚本分配用户数比例,由系统按照比例自动分配用户数;

    3,后者脚本选择LOADGENERATOR时,除了可以选择单个的LOAD GENERATOR外,还可以设置为ALL LOAD GENERATOR,即使用所有的LOADGENERATOR。

    由于这种方式没有用户组的概念,因此在设置SCHEDULE时,不能按组设置,只能按整个场景设置

    Ø GOAL-ORIENTED SCENARIO

    这种方式是基于目标自动创建场景的方式,测试人员只要输入性能测试所要达到的目标,LOADRUNNER就会自动根据目标安排场景的运行;

    采用GOAL-ORIENTED SCENARIO方式创建场景时,需要单击EDIT SCENARIO GOAL按钮定义场景目标,CONTROLLER在执行的时候会根据场景目标的要求,自动加载用户,控制场景的运行;

    VIRTUAL USERS

    以虚拟用户数作为目标,当一个应用对用户数要求比较高时,可以使用这种方式来测试一个应用程序能够允许多少个用户同时运行。基于用户数目标的原理和设定方法比较简单,他和MANUAL SCENARIO WITH PERCENTAGE MODE 方式基本相似,只需要定义要求达到的用户数就可以了。从某种意义上讲,它还不能体现面向目标类型的优势。

    HITS PER SECOND,以每秒点击数作为目标

    TRANSACTIONS PER SECOND,以每秒事务数作为目标

    PAGES PER MINUTE,以每分钟页数作为目标

    以上三种类型都需要用户指定虚拟用户数的范围,CONTROLLER在运行场景的时候,首先加载最小的用户数,如果使用最小的用户数不能达到目标,系统会自动逐渐增加用户直到能够达到设定的目标为止。当加载的用户数达到最大值仍然不能满足要求时,就需要重新设置场景,增加最大用户数。可以通过LOAD BEHAVIOR选项设定三种不同的用户加载策略,如果没有达到目标,LOADRUNNER会重新运行场景,一次加载最大的用户数,尝试是否能够达到目标,如果出现如下情况之一,场景的运行结果都会置于FAILED状态,

    CONTROLLER两次加载了最大的用户数都没有达到目标;

    在运行过程中所有的用户都失败了;

    LOAD GENERATOR数目不能满足要求;

    CONTROLLER在增加用户的过程中,性能指标没有增加;

    CONTROLLER在加载第一批用户后,没有捕获到指标的值;

    TRANSATIONS RESPONSE TIME,以事务响应作为目标,

    主要用于衡量要达到预期的事务响应时间,系统所容纳的最多用户数,如果系统已经加载了最大的用户数,响应时间仍然低于设定的值,说明系统还有能力容纳更多的用户,如果使用一部分用户就达到了设定的响应时间,说明系统是无法容纳设定的最大数量的用户的,必须通过完善应用程序来达到目的;

    多机联合产生负载

    LOADRUNNER对应用程序施压时,采用的方法就是让一台机器模拟很多用户,同时向被测用户发送请求或进行操作。这样,如果一台测试机器模拟的虚拟用户数过多,他本身性能的下降会直接影响测试效果。为了避免这种情况,LOADRUNNER允许使用多台机器运行场景来均衡测试机器的负荷。只要一台机器安装了LOAD GENERATOR并启动了LOADRUNNER AGENT PROCESS进程,就可以被CONTROLLER统一调度来运行场景,CONTROLLER负载收集统一的测试信息和执行结果。

    Ø安装LOAD GENERATOR,如果一台测试机仅用来被CONTROLLER调用执行场景,只需安装LOAD GENERATOR就可以了。

    Ø 在CONTROLLER中创建LOAD GENERATOR

    Ø 在场景中用不同的LOAD GENERATOR联合产生负载

    设定集合点策略

    LOADRUNNER在运行场景的时候,允许测试人员根据项目需要自己设定集合点的并发策略,要设定一个集合点以何种方法运行,在创建或打开脚本中包含集合点的场景时,选择SCENARIOI|RENDEZVOUS命令,可以查看场景中所有脚本中的集合点名称,所属脚本,当前状态和相关的虚拟用户列表信息等,根据系统需求,还可以针对集合点的执行进行设定。

    Ø 单击DISABLE/ENABLE RENDEZVOUS按钮可以选定集合点是否启用;

    Ø 单击DISABLE/ENABLE VUSERS按钮可以设定一个用户是否参与到集合点中;

    Ø 单击POLICY按钮可以设定集合点执行策略。

    n 在POLICY对话框中的TIMEOUT BETWEEN VUSERS文本框中设定了一个超时时间,当第一个用户到达集合点时,系统开始计时。如果在这个设定的时间内没有达到要求的集合点用户数,系统就不在等待,释放用户让场景继续执行;

    启用IP欺骗

    LOADRUNNER进行压力负载测试的时候,是让一台机器模拟成百上千的用户对服务器施压,这样就产生了一个问题,那就是所有用户向服务器发起请求的时候,使用的都是同一个IP地址,即LOAD GENERATOR所在机器的固定IP地址,这是和实际运行环境不符的,而且有些应用系统在设计的时候会根据IP来分配资源,有些还限制同一个IP的多次登陆过程。LOADRUNNER为了解决这个问题,使用了一种称为“IP欺骗(IP SPOOFER)”的技术。也就是让一个LOAD GENERATOR上的虚拟用户模拟从不同的IP来向服务器发起请求,以达到以假乱真的目的。

    配置IP SPOOFER

    LOADRNNER配置动态IP的工具是程序组中的一个小工具-IP WIZARD,它能够指导用户按步骤完成配置过程,这里有三个单选按钮;

    第一个单选按钮CREATE NEW SETTING,用于创建一个新的设置,首次运行时选用;

    第二个单选按钮LOAD PREVIOUS SETTING FROM可以调用以前保存的设置;

    第三个单选按钮RESTORE ORIGINALSET不是用来创建动态IP,而是将设置恢复为原始状态,这个选项主要用于使用后释放IP,如果使用完毕后不释放IP的话,那么这些IP会被一直占用,别人就无法使用了。

    Ø 启用IP欺骗

    在CONTROLLER窗口中,选择SCENARIO|ENABLE IP SPOOFER命令,就可以起用IP欺骗了,在IP欺骗启用后,在CONTROLLER状态栏中会显示相应的状态标识;

    Ø 在OPTIONS中设置IP地址的分配方式;

    创建虚拟IP地址之后,还要选择TOOLS|OPTIONS命令,在弹出的对话框中单击GENERAL标签以设定IP地址的分配方式;

    n IP ADDRESS ALLOCATION PER PROCESS:给每个进程分配不同的IP地址;

    n IP ADDRESS ALLOCATION PER THREAD: 给每个线程分配不同的IP地址;

    一般来说,如果在RUN-TIME SETTING中设置的是以多线程的方式运行,则这里就给每个线程分配不同的IP地址。如果在RUN-TIME SETTING中设置的是以多进程的方式运行,则这里给每个进程分配不同的IP地址;

    注意:只有在CONTROLLER中选择TOOL|EXPERT MODE 命令,才能在OPTIONS对话框中包含设定IP分配的选项;

    控制场景的运行

    按钮开始执行场景以后,LOADRUNNER首先检查场景的配置信息,并激活被测应用,然后将虚拟用户分配到相应的LOAD GENERATOR上。当虚拟用户准备好以后就开始对被测应用施压,在施压的同时LOADRUNNER会完成如下的操作;

    1) 记录在脚本中定义的每个事务的执行时间;

    2) 执行脚本中定义的集合点的功能;

    3) 收集每个虚拟用户发出的告警,错误和提示信息;

    Ø 初始化用户组

    单击START SCENARIO 按钮执行场景时,虚拟用户并没有立刻执行脚本,而是首先执行一个初始化过程,初始化完毕的用户状态会变为READY,只有状态为READY 的用户才能真正开始执行脚本。由于各种条件的限制,场景中用户的初始化过程是无法达到完全同步的,这就造就了用户无法同时运行测试脚本。为了让用户能够同时对被测应用施压,LOADRUNNER提供了初始化用户组的策略,让所有用户在执行脚本之前全部变为READY 状态。

    初始化用户组的方法是在开始运行场景之前,先在RUN选项卡中选中要初始化的用户组,然后单击工具栏的INITIALIZE THE SELECTED VUSERS按钮,或者单击鼠标右键,在弹出的菜单中选择INITIALIZE GROUPS命令,如果初始化成功,用户状态变为READY,如果失败,用户的状态就会变为ERROR。

    Ø 停止场景的运行

    一个场景会在以下三种情况停止运行:

    1) 所有用户都执行完脚本;

    2) 测试人员手动停止了场景的运行;

    3) 执行超时;

    在线监视场景

    注意:必须以被监视机器的管理员身份登陆到CONTROLLER所在机器,才能添加被监视机器的性能计数器;

    Ø 常见的计数器

    1) MEMORY相关,内存问题主要检查应用程序是否存在内存泄露,如果发生了泄露,PROCESS\PRIVATE BYTES计数器和PROCESS\WORKING SET计数器的值往往会升高,同时AVALIABLE BYTES的值会降低.内存泄露应该通过一个长时间的测试来检查,主要测试当所有内存都耗尽时应用程序的反应情况;

    2) PROCESSOR相关,判断应用程序是否存在处理器的瓶颈

    如果PROCESSOR QUEUE LENGTH显示的队列长度保持不变(>=2),且处理器的利用率%PROCESSOR TIME超过90%,那么很可能存在处理器瓶颈;

    如果发现PROCESSOR QUEUE LENGTH显示的队列长度超过2,而处理器利用率却一直很低,那么或许更应该去解决处理器的阻塞问题,处理器一般不是瓶颈;

    如果系统由于应用程序代码效率低下或者系统结构设计有缺陷而导致大量的上下文切换(CONTEXT SWITCHES/SEC,显示的上下文切换次数)比较大,那么就会造成大量的系统资源;

    如果系统吞吐量降低并且CPU的使用率很高,并且此现象发生时切换水平在1500以上,那么意味着上下文切换的次数过高;

    还可以比较CONTEXT SWITCHES/SEC和%PRIVILEGED TIME来判断上下文切换是否过量;如果后者的值超过40%,且上下文切换的速率也很高,那么应该检查为什么会产生这么高的上下文切换;

    3) 网络吞吐量及带宽

    BYTES TOTAL/SEC: 判断网络连接速度是否是瓶颈,可以用该计数器的值和目前网络的带宽比较,相除结果应该小于50%;

    4) 磁盘相关

    判断磁盘瓶颈的方法是通过以下的公式来计算:

    每磁盘的I/O数=[读次数+(4*写次数)]/磁盘个数

    如果计算的每磁盘的I/O数大于磁盘的处理能力,那么磁盘存在瓶颈;

    5) WEB SERVER相关

    6) 数据库服务器相关

    设定监视器选项

    选择TOOLS|OPTION命令,在MONITORS选项卡中可以统一设定监视器的一些参数选项,

    1) TRANSACTION DATA

    用于监视事务图表的数据行为,这些参数不能在场景运行过程中更改,参数修改后需要重新连接虚拟用户的LOADGENERATOR才能生效;

    ENABLE TRASACTION MONITOR:如果选择该选项,场景启动后就自动开始监视事务,默认情况下,该选项是选中的;

    FREQUENCY:设定MONITOR抽样数据产生事务,获取数据点和生成网络资源在线图表的频率.默认为5秒,如果是小的场景建议使用1秒;如果大一些的场景,建议3-5秒;这个参数越低,采样间隔越小,监视图表越精确,网络工作量也就越大;

    2) SERVER RESOURCE MONITORS

    定义了服务器资源监视器的行为,修改该选项对已经被激活的图表不起作用,只对随后被激活的图表起作用;

    DATA SAMPLING RATE:定义了服务器两次采样数据的时间间隔,默认为3秒,这个参数对所有图表都起作用,如果要对单个图表起作用,需要在单个图表的配置属性中定义,

    每个图表都有一个最小的采样频率,如果这里设定的值低于图表的最小采样频率,图表仍然使用最小的采样频率;

    3) ERROR HANDLING

    定义了监视过程中的错误处理方式;

    SEND ERROR TO THE OUTPUT WINDOW:遇到错误时将出错信息输出到OUTPUT窗口;

    POP-UP AN ERROR MASSAGE BOX:遇到错误时弹出错误信息窗口;

    4) DEBUG

    设定DEBUG场景的方式;

    DISPLAY DEBUG MESSAGE:选中该复选框,系统会向输出日志中发送DEBUG相关信息,定义DEBUG的等级

    合并图表

    LOADRUNNER为了便于测试人员比较两个图表数据之间的关系,提供了图表合并的功能,也就是可以将同一个场景中的两个图表中的计数器合并到一个图表中,合并以后的图表共用一个X轴。

    要合并两个图象,只需右键单击一个图表,在弹出的快捷菜单中选择OVERLAY GRAPHS命令,然后在系统提示的对话框中选择另一个图表,并为新图表命名,需要注意的是只有X轴相同的图表才能合并

    其他与监视图表相关的功能

    Ø 穿越防火墙监视图表;

    为了安全起见,运行MONITOR和VUSER的机器安装了防火墙,这样处于防火墙之外的CONTROLLER在控制虚拟用户执行和监视场景的时候就会碰到一些麻烦;

    LOADRUNER通过在防火墙上使用基于HTTPS或者使用标准SSL端口(443)的安全的TCP/IP的协议来解决这个问题。使用LOAD GENERATOR机器或MONITOR机器上的代理充当通信过程的媒介,与MI LISTENER通信。 MI LISTENER是一个需要单独安装的LOADRUNNER组件,它服务于CONTROLLER和LOADRUNNER代理之间,

    如果未安装MI LISTENER组件,LOADRUNNER也可以穿越防火墙实现监控MONITOR和执行VUSERS,这时需要在LOAD GENERATOR 端和CONTROLLER端的防火墙上均打开54345端口;

    Ø 远程监视场景;

    LOADRUNNER提供了一个组件,用于同时通过多个机器上的WEB页面远程监视场景,每个监视还可以根据需要定制不同监视图表

    要完成远程监控,需要一个远程性能监视服务器,(REMOTE PERFORMANCE MONITOR SERVER),它是一个包括很多ASP页面和性能图表过滤器的网站,和CONTROLLER交互数据,并且决定能够在线查看场景的用户数。远程性能监视服务器上必须安装LOADRUNNER的REMOTE PERFORMANCE MONITOR SERVER组件,该组件有如下系统需求:

    • WEB SERVER: IIS5.0
    • 操作系统:WINDOWS 2000SERVER或WINDOWS 2000ADVANCED SERVER
    • 客户端浏览器:IE5.0或NETSCAPE6.2以上;

    使用ANALYSIS分析结果图表

    LOADRUNNER除了将获取的原始数据形成直观的图表外,还对数据进行了一些统计,,例如在多数分析图表下方的图例列表中,给出了最大值,最小值,平均值,中间值和STD等一些统计字段,便于用户分析;

    STD是一个统计学概念,称为标准偏差值,是用来衡量数据的偏离程度的.当平均值不多时,可以从STD指标看出统计图表列数据到底是分散还是集中的.STD越小表示图表的列数据越集中,拿AVERAGE RESPONSE TIME来说,也就表示每个虚拟用户单一的响应时间值大致是差不多的,即被测系统的反应很稳定,没有大起大落;

    1) TRANSACTION PERFORMANCE SUMMARY

    可以基本确认哪个事务的响应时间比较长,一般来说,响应时间长的事务是分析的重点;

    2) AVERAGE TRANSACTION RESPONSE TIME

    可以详细查看每个事务在场景运行中的响应时间,

    3) WEB PAGE BREAKDOWN

    用于分解页面,查看页面中哪些组件导致事务的响应时间比较长,

    • DNS RESOLUTION时间 DNS服务器解析IP地址的时间,这个度量时间可以确定DNS服务器或者DNS服务器的配置是否有问题,如果DNS运行正常,这个值一般比较小;
    • CONNECTION时间 浏览器和WEB SERVER建立初始化连接的时间,这个度量可以判断网络情况,也可以判断WEBSERVER是否响应这个请求;
    • SSL HANDSHAKING 时间 建立SSL连接的时间,使用SSL协议页面比较少,一般应用在HTTPS通信;
    • FTP AUTHENTICATION时间 FTP服务器在处理客户端的命令之前,首先要对客户端进行鉴权,这个度量就是FTP服务器对客户端进行鉴权的时间;
    • FIRST BUFFER时间 指连接建立成功后,从WEB SERVER发出的第一个数据包经过网络传输到客户端,浏览器成功接受到第一个字节的时间.这个度量既包括WEB SERVER的延迟时间,也包括了网络的反应时间.
    • RECEIVE时间 从浏览器收到第一个字节起,直到成功收到最后一个字节,所经历的时间.这个度量和组件大小结合,可以判断网络的质量;
    • CLIENT时间 指请求在客户端的延迟时间,这个延迟可能是浏览器的THINK TIME等引起的
    • ERROR时间 指从发送HTTP请求到HTTP错误信息返回的时间;

    4) TIME TO FIRST BUFFER BREAKDOWN

    可以将页面或组件的时间分解为服务器时间和网络时间,帮助测试人员判断问题缘由到底是服务器还是网络存在瓶颈;

    5) THROUTPUT

    可分析整个压力测试过程中WEB SERVER的吞吐量,即虚拟用户在测试过程中各时刻从服务器上接收到的数据量.

    6) DOWNLOAD COMPONENT SIZE

    页面元素的大小分解和比较

    7) WINDOWS RESOURCE

    系统资源图表,可以监视服务器端的系统资源使用情况,从而判断服务器的CPU,内存等是否是导致性能降低的原因;

    Ø 关于分析图表的几个选项

    • 自动整理合并结果

    在使用ANALYSIS分析场景结果之前,首先要明确结果文件中收集了哪些信息,默认情况下,各个虚拟用户的执行结果数据都是存放在各个虚拟用户所在的机器上的,场景执行结束后,才被系统自动整理合并后放置到结果目录下,LOADRUNNER是否执行这个整理合并操作是受CONTROLLER中的AUTO COLLATE RESULTS选项控制的。该选项设定方法是在RESULTS下选择AUTO COLLATE RESULTS复选框;

    • 设定收集结果信息方式

    对于结果文件大于100MB的大型场景,ANALYSIS加载结果数据时会耗费很长时间,测试人员在等待全部数据加载的同时可以首先查看结果的概要数据,这样,在测试人员浏览概要信息的时候系统会陆续加载其他详细信息数据;

    测试人员可以根据需要设定是否产生概要数据,以及以何种方式显示结果信息,设定入口:菜单 TOOLS|OPTION|RESULT COLLECTION ,

    在DATA SOURCE一栏有三个选项供测试人员选择;

    只生成概要数据;只生成全部详细数据;在生成全部详细数据的同时显示概要数据;

    • 设定数据聚集粒度
    • 使用系统自动聚合的公式自动聚合数据 ;
    • 使用系统自动聚合公式只对WEB数据进行聚合;
    • 单击AGGREGATION CONFIGURATION自己定义聚合方式 ;

    使用ANALYSIS技巧

    Ø 查看图表技巧

    1) 将鼠标放置到图表上需要放大部分的起始位置,然后按住鼠标左键拖动,松开鼠标后鼠标圈住的矩形部分的图表放大显示,便于用户查看图表细节;

    2) 在图例列表中选择一个MEASUREMENT,单击鼠标右键,在系统弹出的菜单中选择CONFIGURE MEASUREMENT命令,之后就可以设定显示颜色和比例,通过设定比例,可以让不同数量级的数据都在图表的主要区域显示,使每个图表的趋势都很明显;

    3) 在图例列表中单击鼠标右键,选择CONFIGURE COLUMN,可以设定在图例列表包含哪些列,以及表格中的图例如何排序等;

    4) 在图表中单击鼠标右键,选择SET FILTER/GROUP BY,可以筛选图表中要显示数据和数据的分组方式;

    Ø 分析图表技巧

    1) 向下钻取图表

    选中一个图表中的某条折线,单击鼠标右键后选择DRILL DOWN,可以对选定的MEASUERMENT J进行向下钻取,钻取的方向可以根据需要进行选择,要取消钻取,需要使用SET FILTER/GROUP BY功能;

    2) 查看原始数据

    在图表下面的RAW DATA或GRAPH DATA中,可以查看图表的原始数据;

    3) 自动关联图表

    在一个图表上单击鼠标右键,在弹出的菜单中选择AUTO COLLATE命令,依据提示进行设定后,系统会自动搜寻和该图表趋势有一定规律的图表,合并到该图表上,该功能便于测试人员分析指标间的联系,

    4) 合并图表

    为了便于分析指标间的相互关系,在ANALYSIS中还可以手动将两个图表合并为一个图表.两个图表合并的条件是具有相同的X轴,合并图表的方法是:在ANALYSIS中用鼠标右键单击想要合并图表重中的一个,在弹出的菜单中选择MERGE GRAPH,根据系统提示选择被合并的图表和合并方式,系统会自动生成新的合并后图表.下面是ANALYSIS图表的3种合并方式

    • OVERLAY

    两个图表合并和共用一个X轴,左边的Y轴上标识当前图表的刻度值,右边的Y轴标识被合并图表的刻度值。当有多个图表被合并时,仍显示一个Y轴刻度,这时可以通过设定图表的显示比例让所有图表都显示在主区域;

    • TILE

    两个图表合并后共用一个X轴,Y轴会被分为两个部分,这样合并的两个图表,看起来相对独立一些,其中一个显示在另一个的上部;

    • CORRELATE

    在合并图表后的图表中,其中一个图表的Y轴作为合并后的Y轴,而另一个图表的Y轴作为合并后图表的X轴,这样合并的图表更能看出两个图表变化趋势之间的关系

    Ø 引入外部数据

    监视场景的时候,可以通过添加计数器的方式监视服务器的系统资源,使用ANALYSIS打开场景的结果文件后,就可以对这些系统资源的数据图表进行分析.

    但有时受客观条件的限制,测试人员无法在LR场景中监视服务器系统资源,这时可以采用一个办法,就是让服务器自己监视自己的资源,并生成相应的CSV文件,当使用ANALYSIS分析结果的时候,把这些单独的CSV文件作为外部数据导入到ANALYSIS中;

    LOADRUNNER提供了ANALYSIS IMPORT DATA工具允许测试人员把一些非自身生成的数据信息引入和集成到ANALYSIS的SESSION中,引入之后,就可以使用ANALYSIS的工具对它们进行查看和分析了。

    工具入口:菜单TOOLS|EXTERNAL MONITORS|IMPORT DATA

    单击ADD FILE 按钮,输入保存的外部数据源文件后,需要在FILE FORMAT中正确选择数据源的格式,否则可能导致引入过程失败;

  • lr性能分析图解释(转)

    2009-05-21 17:21:50

    Loadrunner关联(一)什么时候需要做关联

    1.关联的含义

    关联(correlation):在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关联规则),在服务器所响应的内容中查找,得到相应的值,已变量的形式替换录制时的静态值,从而向服务器发出正确的请求,这种动态获得服务器响应内容的方法被称作关联。

    其实关联也属于一同特殊的参数化,只是与一般的参数化有些不同

    一般的参数化的参数来源于一个文件、一个定义的table、通过sql写的一个结果集等,但关联所获得的参数是服务器响应请求所返回的一个符合条件的、动态的值

    2.什么时候需要做关联

    要想弄清这个问题,我们首先要知道客户端与服务器端的请求与响应的过程

    拿一个登录的过程我们来看一下:

    过程说明:

    客户端发出获得登录页面的请求

    服务器端得到该请求后,返回登录页面,同时动态生成一个Session Id

    当用户输入用户名密码,请求登录时,该Session Id同时被发送到服务器端

    如果该Session Id在当前会话中有效,那么返回登录成功的页面,如果不正确则登录失败

    在第一次录制过程中loadrunner把这个值记录了下来,写到了脚本中,但再次回放时,客户端发出同样的请求,而服务器端再一次动态的生成了Session Id,此时客户端发出的请求就是错误的,为了获得这个动态的Session Id我们这里用到了关联。

    所以我们得出结论:

    当客户端的某个请求是随着服务器端的相应而动态变化的时候,我们就需要用到关联

    当然我们在录制脚本时应该对测试的项目进行适当的了解,知道哪些请求需要用到服务器响应的动态值,如果我们不明确那些值需要做关联的话,我们也可以将脚本录制两遍,通过对比脚本的方法来查找需要关联的部分,但并不是说两次录制的所有不同点都需要关联,这个要具体情况具体分析

  • ip欺骗

    2009-05-21 17:20:28

    Loadrunner关联(一)什么时候需要做关联

    1.关联的含义

    关联(correlation):在脚本回放过程中,客户端发出请求,通过关联函数所定义的左右边界值(也就是关联规则),在服务器所响应的内容中查找,得到相应的值,已变量的形式替换录制时的静态值,从而向服务器发出正确的请求,这种动态获得服务器响应内容的方法被称作关联。

    其实关联也属于一同特殊的参数化,只是与一般的参数化有些不同

    一般的参数化的参数来源于一个文件、一个定义的table、通过sql写的一个结果集等,但关联所获得的参数是服务器响应请求所返回的一个符合条件的、动态的值

    2.什么时候需要做关联

    要想弄清这个问题,我们首先要知道客户端与服务器端的请求与响应的过程

    拿一个登录的过程我们来看一下:

    过程说明:

    客户端发出获得登录页面的请求

    服务器端得到该请求后,返回登录页面,同时动态生成一个Session Id

    当用户输入用户名密码,请求登录时,该Session Id同时被发送到服务器端

    如果该Session Id在当前会话中有效,那么返回登录成功的页面,如果不正确则登录失败

    在第一次录制过程中loadrunner把这个值记录了下来,写到了脚本中,但再次回放时,客户端发出同样的请求,而服务器端再一次动态的生成了Session Id,此时客户端发出的请求就是错误的,为了获得这个动态的Session Id我们这里用到了关联。

    所以我们得出结论:

    当客户端的某个请求是随着服务器端的相应而动态变化的时候,我们就需要用到关联

    当然我们在录制脚本时应该对测试的项目进行适当的了解,知道哪些请求需要用到服务器响应的动态值,如果我们不明确那些值需要做关联的话,我们也可以将脚本录制两遍,通过对比脚本的方法来查找需要关联的部分,但并不是说两次录制的所有不同点都需要关联,这个要具体情况具体分析

251/212>
Open Toolbar