好好学习编码技术、测试理论、英语。

发布新日志

  • 一个小程序

    2007-10-09 15:27:19

    一个小程序就当玩玩的 呵呵

    Imports System

    Module Module1

        Sub Main()
            '声明一个程序信息类 
            Dim info As New System.Diagnostics.ProcessStartInfo()
            '设置外部程序名  
            info.FileName = "notepad.exe"
            '设置外部程序的启动参数(命令行参数)为test.txt  
            info.Arguments = "1.txt"
            '设置外部程序工作目录为   C:\  
            info.WorkingDirectory = "c:\\"
            '声明一个程序类  
            Dim pro As System.Diagnostics.Process
            Try
                ' 
                '启动外部程序  
                ' 
                pro = System.Diagnostics.Process.Start(info)

            Catch e As System.ComponentModel.Win32Exception
                Console.WriteLine("系统找不到指定的程序文件。\r{0}", e)
                Return
              
            End Try
            '打印出外部程序的开始执行时间  
            Console.WriteLine("外部程序的开始执行时间:{0}", pro.StartTime)

            pro.WaitForExit(3000)
            '这里是什么意思???  
            '如果这个外部程序没有结束运行则对其强行终止  
            If (pro.HasExited = False) Then
                Console.WriteLine("由主程序强行终止外部程序的运行!")
                pro.Kill()
            Else
                Console.WriteLine("由外部程序正常退出!")
            End If
            Console.WriteLine("外部程序的结束运行时间:{0}", pro.ExitTime)
            Console.WriteLine("外部程序在结束运行时的返回值:{0}", pro.ExitCode)
        End Sub

    End Module

  • ORACLE函数大全(转载)

    2007-09-30 09:52:42

    7-10月做了一个vb.net+oracle的项目,学习一些oracle的函数。转载下面的文章学习一下

     SQL中的单记录函数
    1.ASCII
    返回与指定的字符对应的十进制数;
    SQL> select ascii('A') A,ascii('a') a,ascii('0') zero,ascii(' ') space from dual;

            A         A      ZERO     SPACE
    --------- --------- --------- ---------
           65        97        48        32


    2.CHR
    给出整数,返回对应的字符;
    SQL> select chr(54740) zhao,chr(65) chr65 from dual;

    ZH C
    -- -
    赵 A

    3.CONCAT
    连接两个字符串;
    SQL> select concat('010-','88888888')||'转23'  高乾竞电话 from dual;

    高乾竞电话
    ----------------
    010-88888888转23

    4.INITCAP
    返回字符串并将字符串的第一个字母变为大写;
    SQL> select initcap('smith') upp from dual;

    UPP
    -----
    Smith


    5.INSTR(C1,C2,I,J)
    在一个字符串中搜索指定的字符,返回发现指定的字符的位置;
    C1    被搜索的字符串
    C2    希望搜索的字符串
    I     搜索的开始位置,默认为1
    J     出现的位置,默认为1
    SQL> select instr('oracle traning','ra',1,2) instring from dual;

     INSTRING
    ---------
            9


    6.LENGTH
    返回字符串的长度;
    SQL> select name,length(name),addr,length(addr),sal,length(to_char(sal)) from gao.nchar_tst;

    NAME   LENGTH(NAME) ADDR             LENGTH(ADDR)       SAL LENGTH(TO_CHAR(SAL))
    ------ ------------ ---------------- ------------ --------- --------------------
    高乾竞            3 北京市海锭区                6   9999.99                    7

     

    7.LOWER
    返回字符串,并将所有的字符小写
    SQL> select lower('AaBbCcDd')AaBbCcDd from dual;

    AABBCCDD
    --------
    aabbccdd


    8.UPPER
    返回字符串,并将所有的字符大写
    SQL> select upper('AaBbCcDd') upper from dual;

    UPPER
    --------
    AABBCCDD

     

    9.RPAD和LPAD(粘贴字符)
    RPAD  在列的右边粘贴字符
    LPAD  在列的左边粘贴字符
    SQL> select lpad(rpad('gao',10,'*'),17,'*')from dual;

    LPAD(RPAD('GAO',1
    -----------------
    *******gao*******
    不够字符则用*来填满


    10.LTRIM和RTRIM
    LTRIM  删除左边出现的字符串
    RTRIM  删除右边出现的字符串
    SQL> select ltrim(rtrim('   gao qian jing   ',' '),' ') from dual;

    LTRIM(RTRIM('
    -------------
    gao qian jing


    11.SUBSTR(string,start,count)
    取子字符串,从start开始,取count个
    SQL> select substr('13088888888',3,8) from dual;

    SUBSTR('
    --------
    08888888


    12.REPLACE('string','s1','s2')
    string   希望被替换的字符或变量
    s1       被替换的字符串
    s2       要替换的字符串
    SQL> select replace('he love you','he','i') from dual;

    REPLACE('H
    ----------
    i love you


    13.SOUNDEX
    返回一个与给定的字符串读音相同的字符串
    SQL> create table table1(xm varchar(8));
    SQL> insert into table1 values('weather');
    SQL> insert into table1 values('wether');
    SQL> insert into table1 values('gao');

    SQL> select xm from table1 where soundex(xm)=soundex('weather');

    XM
    --------
    weather
    wether


    14.TRIM('s' from 'string')
    LEADING   剪掉前面的字符
    TRAILING  剪掉后面的字符
    如果不指定,默认为空格符

    15.ABS
    返回指定值的绝对值
    SQL> select abs(100),abs(-100) from dual;

     ABS(100) ABS(-100)
    --------- ---------
          100       100


    16.ACOS
    给出反余弦的值
    SQL> select acos(-1) from dual;

     ACOS(-1)
    ---------
    3.1415927


    17.ASIN
    给出反正弦的值
    SQL> select asin(0.5) from dual;

    ASIN(0.5)
    ---------
    .52359878


    18.ATAN
    返回一个数字的反正切值
    SQL> select atan(1) from dual;

      ATAN(1)
    ---------
    .78539816


    19.CEIL
    返回大于或等于给出数字的最小整数
    SQL> select ceil(3.1415927) from dual;

    CEIL(3.1415927)
    ---------------
                  4


    20.COS
    返回一个给定数字的余弦
    SQL> select cos(-3.1415927) from dual;

    COS(-3.1415927)
    ---------------
                 -1


    21.COSH
    返回一个数字反余弦值
    SQL> select cosh(20) from dual;

     COSH(20)
    ---------
    242582598


    22.EXP
    返回一个数字e的n次方根
    SQL> select exp(2),exp(1) from dual;

       EXP(2)    EXP(1)
    --------- ---------
    7.3890561 2.7182818


    23.FLOOR
    对给定的数字取整数
    SQL> select floor(2345.67) from dual;

    FLOOR(2345.67)
    --------------
              2345


    24.LN
    返回一个数字的对数值
    SQL> select ln(1),ln(2),ln(2.7182818) from dual;

        LN(1)     LN(2) LN(2.7182818)
    --------- --------- -------------
            0 .69314718     .99999999


    25.LOG(n1,n2)
    返回一个以n1为底n2的对数
    SQL> select log(2,1),log(2,4) from dual;

     LOG(2,1)  LOG(2,4)
    --------- ---------
            0         2


    26.MOD(n1,n2)
    返回一个n1除以n2的余数
    SQL> select mod(10,3),mod(3,3),mod(2,3) from dual;

    MOD(10,3)  MOD(3,3)  MOD(2,3)
    --------- --------- ---------
            1         0         2


    27.POWER
    返回n1的n2次方根
    SQL> select power(2,10),power(3,3) from dual;

    POWER(2,10) POWER(3,3)
    ----------- ----------
           1024         27


    28.ROUND和TRUNC
    按照指定的精度进行舍入
    SQL> select round(55.5),round(-55.4),trunc(55.5),trunc(-55.5) from dual;

    ROUND(55.5) ROUND(-55.4) TRUNC(55.5) TRUNC(-55.5)
    ----------- ------------ ----------- ------------
             56          -55          55          -55


    29.SIGN
    取数字n的符号,大于0返回1,小于0返回-1,等于0返回0
    SQL> select sign(123),sign(-100),sign(0) from dual;

    SIGN(123) SIGN(-100)   SIGN(0)
    --------- ---------- ---------
            1         -1         0


    30.SIN
    返回一个数字的正弦值
    SQL> select sin(1.57079) from dual;

    SIN(1.57079)
    ------------
               1


    31.SIGH
    返回双曲正弦的值
    SQL> select sin(20),sinh(20) from dual;

      SIN(20)  SINH(20)
    --------- ---------
    .91294525 242582598


    32.SQRT
    返回数字n的根
    SQL> select sqrt(64),sqrt(10) from dual;

     SQRT(64)  SQRT(10)
    --------- ---------
            8 3.1622777


    33.TAN
    返回数字的正切值
    SQL> select tan(20),tan(10) from dual;

      TAN(20)   TAN(10)
    --------- ---------
    2.2371609 .64836083


    34.TANH
    返回数字n的双曲正切值
    SQL> select tanh(20),tan(20) from dual;

     TANH(20)   TAN(20)
    --------- ---------
            1 2.2371609

     

    35.TRUNC
    按照指定的精度截取一个数
    SQL> select trunc(124.1666,-2) trunc1,trunc(124.16666,2) from dual;

       TRUNC1 TRUNC(124.16666,2)
    --------- ------------------
          100             124.16

     

    36.ADD_MONTHS
    增加或减去月份
    SQL> select to_char(add_months(to_date('199912','yyyymm'),2),'yyyymm') from dual;

    TO_CHA
    ------
    200002
    SQL> select to_char(add_months(to_date('199912','yyyymm'),-2),'yyyymm') from dual;

    TO_CHA
    ------
    199910


    37.LAST_DAY
    返回日期的最后一天
    SQL> select to_char(sysdate,'yyyy.mm.dd'),to_char((sysdate)+1,'yyyy.mm.dd') from dual;

    TO_CHAR(SY TO_CHAR((S
    ---------- ----------
    2004.05.09 2004.05.10
    SQL> select last_day(sysdate) from dual;

    LAST_DAY(S
    ----------
    31-5月 -04


    38.MONTHS_BETWEEN(date2,date1)
    给出date2-date1的月份
    SQL> select months_between('19-12月-1999','19-3月-1999') mon_between from dual;

    MON_BETWEEN
    -----------
              9
    SQL>selectmonths_between(to_date('2000.05.20','yyyy.mm.dd'),to_date('2005.05.20','yyyy.mm.dd')) mon_betw from dual;

     MON_BETW
    ---------
          -60


    39.NEW_TIME(date,'this','that')
    给出在this时区=other时区的日期和时间
    SQL> select to_char(sysdate,'yyyy.mm.dd hh24:mi:ss') bj_time,to_char(new_time
      2  (sysdate,'PDT','GMT'),'yyyy.mm.dd hh24:mi:ss') los_angles from dual;

    BJ_TIME             LOS_ANGLES
    ------------------- -------------------
    2004.05.09 11:05:32 2004.05.09 18:05:32


    40.NEXT_DAY(date,'day')
    给出日期date和星期x之后计算下一个星期的日期
    SQL> select next_day('18-5月-2001','星期五') next_day from dual;

    NEXT_DAY
    ----------
    25-5月 -01

     

    41.SYSDATE
    用来得到系统的当前日期
    SQL> select to_char(sysdate,'dd-mm-yyyy day') from dual;

    TO_CHAR(SYSDATE,'
    -----------------
    09-05-2004 星期日
    trunc(date,fmt)按照给出的要求将日期截断,如果fmt='mi'表示保留分,截断秒
    SQL> select to_char(trunc(sysdate,'hh'),'yyyy.mm.dd hh24:mi:ss') hh,
      2  to_char(trunc(sysdate,'mi'),'yyyy.mm.dd hh24:mi:ss') hhmm from dual;

    HH                  HHMM
    ------------------- -------------------
    2004.05.09 11:00:00 2004.05.09 11:17:00

     

    42.CHARTOROWID
    将字符数据类型转换为ROWID类型
    SQL> select rowid,rowidtochar(rowid),ename from scott.emp;

    ROWID              ROWIDTOCHAR(ROWID) ENAME
    ------------------ ------------------ ----------
    AAAAfKAACAAAAEqAAA AAAAfKAACAAAAEqAAA SMITH
    AAAAfKAACAAAAEqAAB AAAAfKAACAAAAEqAAB ALLEN
    AAAAfKAACAAAAEqAAC AAAAfKAACAAAAEqAAC WARD
    AAAAfKAACAAAAEqAAD AAAAfKAACAAAAEqAAD JONES


    43.CONVERT(c,dset,sset)
    将源字符串 sset从一个语言字符集转换到另一个目的dset字符集
    SQL> select convert('strutz','we8hp','f7dec') "conversion" from dual;

    conver
    ------
    strutz


    44.HEXTORAW
    将一个十六进制构成的字符串转换为二进制


    45.RAWTOHEXT
    将一个二进制构成的字符串转换为十六进制

     

    46.ROWIDTOCHAR
    将ROWID数据类型转换为字符类型

     

    47.TO_CHAR(date,'format')
    SQL> select to_char(sysdate,'yyyy/mm/dd hh24:mi:ss') from dual;

    TO_CHAR(SYSDATE,'YY
    -------------------
    2004/05/09 21:14:41

     

    48.TO_DATE(string,'format')
    将字符串转化为ORACLE中的一个日期


    49.TO_MULTI_BYTE
    将字符串中的单字节字符转化为多字节字符
    SQL>  select to_multi_byte('高') from dual;

    TO
    --


    50.TO_NUMBER
    将给出的字符转换为数字
    SQL> select to_number('1999') year from dual;

         YEAR
    ---------
         1999


    51.BFILENAME(dir,file)
    指定一个外部二进制文件
    SQL>insert into file_tb1 values(bfilename('lob_dir1','image1.gif'));


    52.CONVERT('x','desc','source')
    将x字段或变量的源source转换为desc
    SQL> select sid,serial#,username,decode(command,
      2  0,'none',
      3  2,'insert',
      4  3,
      5  'select',
      6  6,'update',
      7  7,'delete',
      8  8,'drop',
      9  'other') cmd  from v$session where type!='background';

          SID   SERIAL# USERNAME                       CMD
    --------- --------- ------------------------------ ------
            1         1                                none
            2         1                                none
            3         1                                none
            4         1                                none
            5         1                                none
            6         1                                none
            7      1275                                none
            8      1275                                none
            9        20 GAO                            select
           10        40 GAO                            none


    53.DUMP(s,fmt,start,length)
    DUMP函数以fmt指定的内部数字格式返回一个VARCHAR2类型的值
    SQL> col global_name for a30
    SQL> col dump_string for a50
    SQL> set lin 200
    SQL> select global_name,dump(global_name,1017,8,5) dump_string from global_name;

    GLOBAL_NAME                    DUMP_STRING
    ------------------------------ --------------------------------------------------
    ORACLE.WORLD                   Typ=1 Len=12 CharacterSet=ZHS16GBK: W,O,R,L,D


    54.EMPTY_BLOB()和EMPTY_CLOB()
    这两个函数都是用来对大数据类型字段进行初始化操作的函数


    55.GREATEST
    返回一组表达式中的最大值,即比较字符的编码大小.
    SQL> select greatest('AA','AB','AC') from dual;

    GR
    --
    AC
    SQL> select greatest('啊','安','天') from dual;

    GR
    --


    56.LEAST
    返回一组表达式中的最小值
    SQL> select least('啊','安','天') from dual;

    LE
    --


    57.UID
    返回标识当前用户的唯一整数
    SQL> show user
    USER 为"GAO"
    SQL> select username,user_id from dba_users where user_id=uid;

    USERNAME                         USER_ID
    ------------------------------ ---------
    GAO                                   25

     

    58.USER
    返回当前用户的名字
    SQL> select user from  dual;

    USER
    ------------------------------
    GAO


    59.USEREVN
    返回当前用户环境的信息,opt可以是:
    ENTRYID,SESSIONID,TERMINAL,ISDBA,LABLE,LANGUAGE,CLIENT_INFO,LANG,VSIZE
    ISDBA  查看当前用户是否是DBA如果是则返回true
    SQL> select userenv('isdba') from dual;

    USEREN
    ------
    FALSE
    SQL> select userenv('isdba') from dual;

    USEREN
    ------
    TRUE
    SESSION
    返回会话标志
    SQL> select userenv('sessionid') from dual;

    USERENV('SESSIONID')
    --------------------
                     152
    ENTRYID
    返回会话人口标志
    SQL> select userenv('entryid') from dual;

    USERENV('ENTRYID')
    ------------------
                     0
    INSTANCE
    返回当前INSTANCE的标志
    SQL> select userenv('instance') from dual;

    USERENV('INSTANCE')
    -------------------
                      1
    LANGUAGE
    返回当前环境变量
    SQL> select userenv('language') from dual;

    USERENV('LANGUAGE')
    ----------------------------------------------------
    SIMPLIFIED CHINESE_CHINA.ZHS16GBK
    LANG
    返回当前环境的语言的缩写
    SQL> select userenv('lang') from dual;

    USERENV('LANG')
    ----------------------------------------------------
    ZHS
    TERMINAL
    返回用户的终端或机器的标志
    SQL> select userenv('terminal') from dual;

    USERENV('TERMINA
    ----------------
    GAO
    VSIZE(X)
    返回X的大小(字节)数
    SQL> select vsize(user),user from dual;

    VSIZE(USER) USER
    ----------- ------------------------------
              6 SYSTEM

     

    60.AVG(DISTINCT|ALL)
    all表示对所有的值求平均值,distinct只对不同的值求平均值
    SQLWKS> create table table3(xm varchar(8),sal number(7,2));
    语句已处理。
    SQLWKS>  insert into table3 values('gao',1111.11);
    SQLWKS>  insert into table3 values('gao',1111.11);
    SQLWKS>  insert into table3 values('zhu',5555.55);
    SQLWKS> commit;

    SQL> select avg(distinct sal) from gao.table3;

    AVG(DISTINCTSAL)
    ----------------
             3333.33

    SQL> select avg(all sal) from gao.table3;

    AVG(ALLSAL)
    -----------
        2592.59


    61.MAX(DISTINCT|ALL)
    求最大值,ALL表示对所有的值求最大值,DISTINCT表示对不同的值求最大值,相同的只取一次
    SQL> select max(distinct sal) from scott.emp;

    MAX(DISTINCTSAL)
    ----------------
                5000


    62.MIN(DISTINCT|ALL)
    求最小值,ALL表示对所有的值求最小值,DISTINCT表示对不同的值求最小值,相同的只取一次
    SQL> select min(all sal) from gao.table3;

    MIN(ALLSAL)
    -----------
        1111.11


    63.STDDEV(distinct|all)
    求标准差,ALL表示对所有的值求标准差,DISTINCT表示只对不同的值求标准差
    SQL> select stddev(sal) from scott.emp;

    STDDEV(SAL)
    -----------
      1182.5032

    SQL> select stddev(distinct sal) from scott.emp;

    STDDEV(DISTINCTSAL)
    -------------------
               1229.951

     

    64.VARIANCE(DISTINCT|ALL)
    求协方差

    SQL> select variance(sal) from scott.emp;

    VARIANCE(SAL)
    -------------
        1398313.9


    65.GROUP BY
    主要用来对一组数进行统计
    SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno;

       DEPTNO  COUNT(*)  SUM(SAL)
    --------- --------- ---------
           10         3      8750
           20         5     10875
           30         6      9400

     

    66.HAVING
    对分组统计再加限制条件
    SQL> select deptno,count(*),sum(sal) from scott.emp group by deptno having count(*)>=5;

       DEPTNO  COUNT(*)  SUM(SAL)
    --------- --------- ---------
           20         5     10875
           30         6      9400
    SQL> select deptno,count(*),sum(sal) from scott.emp having count(*)>=5 group by deptno ;

       DEPTNO  COUNT(*)  SUM(SAL)
    --------- --------- ---------
           20         5     10875
           30         6      9400


    67.ORDER BY
    用于对查询到的结果进行排序输出
    SQL> select deptno,ename,sal from scott.emp order by deptno,sal desc;

       DEPTNO ENAME            SAL
    --------- ---------- ---------
           10 KING            5000
           10 CLARK           2450
           10 MILLER          1300
           20 SCOTT           3000
           20 FORD            3000
           20 JONES           2975
           20 ADAMS           1100
           20 SMITH            800
           30 BLAKE           2850
           30 ALLEN           1600
           30 TURNER          1500
           30 WARD            1250
           30 MARTIN          1250
           30 JAMES            950

  • EXCEL使用技巧(转载)

    2007-09-29 17:54:49

    测试人员如果使用excel构造测试用例肯定希望能自动填充一些数据,或者生成一些有规律的测试数据。excel真好具备这些功能。

     1、如何在已有的单元格中批量加入一段固定字符?

      例如:在单位的人事资料,在excel中输入后,由于上级要求在原来的职称证书的号码全部再加两位,即要在每个人的证书号码前再添上两位数13,如果一个一个改的话实在太麻烦了,那么我们可以用下面的办法,省时又省力:

       1)假设证书号在A列,在A列后点击鼠标右键,插入一列,为B列 ;

       2)在B2单元格写入: ="13" & A2 后回车;

       3)看到结果为 13xxxxxxxxxxxxx 了吗?鼠标放到B2位置,单元格的下方不是有一个小方点吗,按着鼠标左键往下拖动直到结束。当你放开鼠标左键时就全部都改好了。 若是在原证书号后面加13 则在B2单元格中写入:=A2 & “13” 后回车。

       2、如何设置文件下拉窗口的最下面的最近运行的文件名个数?

       打开“工具”,选“选项”,再选“常规”,在“最近使用的文件清单”下面的文件个数输入框中改变文件数目即可。若不在菜单中显示最近使用的文件名,则将“最近使用的文件清单”前的复选框去掉即可。

       3、在EXCEL中输入如“1-1”、“1-2”之类的格式后它即变成1月1日,1月2日等日期形式,怎么办?

      这是由于EXCEL自动识别为日期格式所造成,你只要点击主菜单的“格式”菜单,选“单元格”,再在“数字”菜单标签下把该单元格的格式设成文本格式就行了。

       4、在EXCEL中如何使它象WORD一样的自动定时保存文件?

       点击“工具”菜单“自动保存”项,设置自动保存文件夹的间隔时间。如果在“工具”菜单下没有“自动保存”菜单项,那么执行“工具”菜单下“加载宏...”选上“自动保存”,“确定”。然后进行设置即可。

       5、用Excel做多页的表格时,怎样像Word的表格那样做一个标题,即每页的第一行(或几行)是一样的。但是不是用页眉来完成?

       在EXCEL的文件菜单-页面设置-工作表-打印标题;可进行顶端或左端标题设置,通过按下折叠对话框按钮后,用鼠标划定范围即 可。这样Excel就会自动在各页上加上你划定的部分作为表头。

       6、在Excel中如何设置加权平均?

       加权平均在财务核算和统计工作中经常用到,并不是一项很复杂的计算,关键是要理解加权平均值其实就是总量值(如金额)除以总数量得出的单位平均值,而不是简单的将各个单位值(如单价)平均后得到的那个单位值。在Excel中可设置公式解决(其实就是一个除法算式),分母是各个量值之和,分子是相应的各个数量之和,它的结果就是这些量值的加权平均值。

       7、如果在一个Excel文件中含有多个工作表,如何将多个工作表一次设置成同样的页眉和页脚?如何才能一次打印多个工作表?

       把鼠标移到工作表的名称处(若你没有特别设置的话,Excel自动设置的名称是“sheet1、sheet2、sheet3.......”),然后点右键,在弹出的菜单中选择“选择全部工作表”的菜单项,这时你的所有操作都是针对全部工作表了,不管是设置页眉和页脚还是打印你工作表。

       8、EXCEL中有序号一栏,由于对表格进行调整,序号全乱了,可要是手动一个一个改序号实在太慢太麻烦,用什么方法可以快速解决?

       如果序号是不应随着表格其他内容的调整而发生变化的话,那么在制作EXCEL表格时就应将序号这一字段与其他字段分开,如在“总分”与“排名”之间空开一列,为了不影响显示美观,可将这一空的列字段设为隐藏,这样在调整表格(数据清单)的内容时就不会影响序号了。

       9、用Excel2000做成的工资表,只有第一个人有工资条的条头(如编号、姓名、岗位工资.......),想输出成工资条的形式。怎么做?

       这个问题应该这样解决:先复制一张工资表,然后在页面设置中选中工作表选项,设置打印工作表行标题,选好工资条的条头,然后在每一个人之间插入行分页符,再把页长设置成工资条的高度即可。 使用自定义方式重装了一遍中文office97,Excel的打印纸选项中只有A4一种,怎么办? 随便安装一个打印机驱动程序就可以了。

       10、在Excel中小数点无法输入,按小数点,显示的却是逗号,无论怎样设置选项都无济于事,该怎么办?

       这是一个比较特殊的问题,我曾为此花了十几个小时的时间,但说白了很简单。在Windows的控制面板中,点击“区域设置”图标,在弹出的“区域设置属性”对话面板上在“区域设置”里选择“中文(中国)”,在“区域设置属性”对话面板上在“数字”属性里把小数点改为“.”(未改前是“,”),按“确定”按钮结束。这样再打开Excel就一切都正常了。

       11、如何快速选取特定区域?

       使用F5键可以快速选取特定区域。例如,要选取A2:A1000,最简便的方法是按F5键,出现“定位”窗口,在“引用”栏内输入需选取的区域A2:A1000。

       12、如何快速返回选中区域?

       按Ctr+BacksPae(即退格键)。

       13、如何快速定位到单元格?

      方法一:按F5键,出现“定位”对话框,在引用栏中输入欲跳到的单元格地址,单市“确定”按钮即可。

       方法二:单击编辑栏左侧单元格地址框,输入单元格地址即可。

       14、“Ctrl+*”的特殊功用

       一般来说,当处理一个工作表中有很多数据的表格时,通过选定表格中某个单元格,然后按下 Ctrl+* 键可选定整个表格。Ctfl+* 选定的区域是这样决定的:根据选定单元格向四周辐射所涉及到的有数据单元格的最大区域。

      15.如何快速选取工作表中所有包含公式的单元格?

       有时,需要对工作表中所有包含公式的单元格加以保护,或填入与其他单元格不同的颜色,以提醒用户注意不能在有此颜色的区域内输入数据。以下方法可以帮助快速选取所有包含公式的单元格:≡瘛氨嗉保堋岸ㄎ弧保セ鳌岸ㄎ惶跫卑磁ィ凇岸ㄎ惶跫倍曰翱蛑醒≡瘛肮健毕睿础叭范ā卑磁ゼ纯伞?

       16、如何在不同单元格中快速输入同一数内容?

      选定单元格区域,输入值,然后按 Ctrl+ Ener键,即可实现在选定的单元格区域中一次性输入相同的值。

       17、只记得函数的名称,但记不清函数的参数了,怎么办?

       如果你知道所要使用函数的名字,但又记不清它的所有参数格式,那么可以用键盘快捷键把参数粘贴到编辑栏内。

       具体方法是:在编辑栏中输入一个等号其后接函数名,然后按 Ctr+ A键,Excel则自动进入“函数指南——步骤 2之2”。当使用易于记忆的名字且具有很长一串参数的函数时,上述方法显得特别有用。

       18、如何把选定的一个或多个单元格拖放至新的位置?

       按住Shift键可以快速修改单元格内容的次序。

       具体方法是: 选定单元格,按下Shift键,移动鼠标指针至单元格边缘,直至出现拖放指针箭头(空心箭头),然后按住鼠标左键进行拖放操作。上下拖拉时鼠标在单元格间边界处会变为一个水平“工”状标志,左右拖拉时会变为垂直“工”状标志,释放鼠标按钮完成操作后,选定的一个或多个单元格就被拖放至新的位置。

       19、如何让屏幕上的工作空间变大?

       可以将不用的工具栏隐藏,也可以极大化Excel窗口,或者在“视图”菜单中选择“全屏显示”命令。

       20、如何使用快显菜单?

       快显菜单中包括了一些操作中最常用的命令,利用它们可以大大提高操作效率。首先选定一个区域,然后单击鼠标右健即可调出快显菜单,根据操作需要选择不同命令。

      21、如何使用快显菜单?

       快显菜单中包括了一些操作中最常用的命令,利用它们可以大大提高操作效率。首先选定一个区域,然后单击鼠标右健即可调出快显菜单,根据操作需要选择不同命令。

      22、如何防止Excel自动打开太多文件?

       当Excel启动时,它会自动打开Xlstart目录下的所有文件。当该目录下的文件过多时,Excel加载太多文件不但费时而且还有可能出错。解决方法是将不该位于Xlstart目录下的文件移走。另外,还要防止EXcel打开替补启动目录下的文件:选择“工具”\“选项”\“普通”,将“替补启动目录”一栏中的所有内容删除。

      23、如何去掉网格线?

       1)除去编辑窗口中的表格线

       单击“工具”菜单中的“选项”,再选中“视图”,找到“网格线”,使之失效;

       2)除去打印时的未定义表格线

       有时会出现这样的情况:你在编辑时未定义的表格线(在编辑窗中看到的也是淡灰色表格线),一般情况下在打印时是不会打印出来的,可有时却偏偏不听使唤给打印出来了,特别是一些所谓的“电脑”VCD中编辑的Excel表格更是这样。要除去这些表格线,只要在单击“文件”、“页面设置”、“工作表”菜单,点击一下“网格线”左边的选择框,取消选择“网格线”就行了。

      24、如何快速格式化报表?

       为了制作出美观的报表,需要对报表进行格式化。有快捷方法,即自动套用Excel预设的表格样式。方法是: 选定操作区域,选取“格式”菜单中的“自动套用格式”命令,在格式列表框中选取一款你满意的格式样式,按“确定”按钮即可。要注意的是,格式列表框下面有包括“数字”、“边框线”、“字体”等6个“应用格式种类”选项,若某项前面的“x”不出现,则在套用表格样式时就不会用该项。

      25、如何快速地复制单元格的格式?

       要将某一格式化操作复制到另一部分数据上,可使用“格式刷”按钮。选择含有所需源格式的单元格,单击工具条上的“格式刷”按钮,此时鼠标变成了刷子形状,然后单击要格式化的单元格即可将格式拷贝过去。

      26、如何为表格添加斜线?

      一般我们习惯表格上有斜线,而工作表本身并没有提供该功能。其实,我们可以使用绘图工具来实现: 单击“绘图”按钮,选取“直线”,鼠标变成十字型.将其移至要添加斜线的开始位置,按住鼠标左键拖动至终止位置,释放鼠标,斜线就画出来了。另外,使用“文字框”按钮可以方便地在斜线上下方添加文字,但文字周围有边框,要想取消它,可选中文字框,调出快显菜单,选择“对象格式”\“图案”,选择“无边框”项即可。

      27、如何快速地将数字作为文本输入?

       在输入数字前加一个单引号“”’,可以强制地将数字作为文本输入。

      28、如何定义自己的函数?

      用户在Excel中可以自定义函数。切换至 Visual Basic模块,或插入一页新的模块表(Module),在出现的空白程序窗口中键入自定义函数VBA程序,按Enter确认后完成编 写工作,Excel将自动检查其正确性。此后,在同一工作薄内,你就可以与使用Exed内部函数一样在工作表中使用自定义函数,如:

      Function Zm(a)

      If a< 60 Then im=‘不及格”

       Else Zm=“及格”

      End If

      End Function

      29、如何在一个与自定义函数驻留工作簿不同的工作簿内的工作表公式中调用自定义 函数?

       可在包含自定义函数的工作薄打开的前提下,采用链接的方法(也就是在调用函数时加上该函数所在的工作簿名)。假设上例中的自定义函数Zm所在工作薄为MYUDF.XLS,现要在另一不同工作簿中的工作表公式中调用Zm函数,应首先确保MYUDF.XLS被打开,然后使用下述链接的方法: =MYUDF.XLS! ZM(b2)

      30、如何快速输入数据序列?

       如果你需要输入诸如表格中的项目序号、日期序列等一些特殊的数据系列,千万别逐条输入,为何不让Excel自动填充呢?在第一个单元格内输入起始数据,在下一个单元格内输入第二个数据,选定这两个单元格,将光标指向单元格右下方的填充柄,沿着要填充的方向拖动填充柄,拖过的单元格中会自动按Excel内部规定的序列进行填充。如果能将自己经常要用到的某些有规律的数据(如办公室人员名单),定义成序列,以备日后自动填充,岂不一劳永逸!选择“工具”菜单中的“选项”命令,再选择“自定义序列”标签, 在输入框中输入新序列,注意在新序列各项2间要输入半角符号的逗号加以分隔(例如:张三,李四,王二……),单击“增加”按钮将输入的序列保存起来。

      31、使用鼠标右键拖动单元格填充柄

       上例中,介绍了使用鼠标左键拖动单元格填充柄自动填充数据序列的方法。其实,使用鼠标右键拖动单元格填充柄则更具灵活性。在某单元格内输入数据,按住鼠标右键沿着要填充序列的方向拖动填充柄,将会出现包含下列各项的菜单:复制单元格、以序列方式填充、以格式填充、以值填充;以天数填充、以工作日该充、以月该充、以年填充;序列……此时,你可以根据需要选择一种填充方式。

      32.如果你的工作表中已有某个序列项,想把它定义成自动填充序列以备后用,是否需要按照上面介绍的自定义序列的方法重新输入这些序列项?

       不需要。有快捷方法:选定包含序列项的单元格区域,选择“工具”\“选项”\“自定义序列”,单击“引入”按钮将选定区域的序列项添加至“自定义序列”对话框,按“确定”按钮返回工作表,下次就可以用这个序列项了。

      33、上例中,如果你已拥育的序列项中含有许多重复项,应如何处理使其没有重复项,以便使用“引入”的方法快速创建所需的自定义序列?

       选定单元格区域,选择“数据”\“筛选”\“高级筛选”,选定“不选重复的记录”选项,按“确定”按钮即可。

      34、如何对工作簿进行安全保护?

       如果你不想别人打开或修改你的工作簿,那么想法加个密码吧。打开工作薄,选择“文件”菜单中的“另存为”命令,选取“选项”,根据用户的需要分别输入“打开文件口令”或“修改文件D令”,按“确定”退出。

      工作簿(表)被保护之后,还可对工作表中某些单元格区域的重要数据进行保护,起到双重保护的功能,此时你可以这样做:首先,选定需保护的单元格区域,选取“格式”菜单中的“单元格”命令,选取“保护”,从对话框中选取“锁定”,单由“确定”按钮退出。然后选取“工具”菜单中的“保护”命令,选取“保护工作表”,根据提示两次输入口令后退出。

      注意:不要忘记你设置有“口令”。

      35、如何使单元格中的颜色和底纹不打印出来?

       对那些加了保护的单元格,还可以设置颜色和底纹,以便让用户一目了然,从颜色上看出那些单元格加了保护不能修改,从而可增加数据输入时的直观感觉。但却带来了问题,即在黑白打印时如果连颜色和底纹都打出来,表格的可视性就大打折扣。解决办法是:选择“文件”\“页面设置”\“工作表”,在“打印”栏内选择“单元格单色打印”选项。之后,打印出来的表格就面目如初了。

      36、工作表保护的口令忘记了怎么办?

       如果你想使用一个保护了的工作表,但口令又忘记了,有办法吗?有。选定工作表,选择“编辑”\“复制”、“粘贴”,将其拷贝到一个新的工作薄中(注意:一定要是新工作簿),即可超越工作表保护。当然,提醒你最好不用这种方法盗用他人的工作表。

      37、“$”的功用

       Excel一般使用相对地址来引用单元格的位置,当把一个含有单元格地址的公式拷贝到一个新的位置,公式中的单元格地址会随着改变。你可以在列号或行号前添加符号 “$”来冻结单元格地址,使之在拷贝时保持固定不变。

      38、如何用汉字名称代替单元格地址?

       如果你不想使用单元格地址,可以将其定义成一个名字。

       定义名字的方法有两种:一种是选定单元格区域后在“名字框”直接输入名字,另一种是选定想要命名的单元格区域,再选择“插入”\“名字”\“定义”,在“当前工作簿中名字”对话框内键人名字即可。使用名字的公式比使用单元格地址引用的公式更易于记忆和阅读,比如公式“=SUM(实发工资)”显然比用单元格地址简单直观,而且不易出错。

      39、如何在公式中快速输入不连续的单元格地址?

       在SUM函数中输入比较长的单元格区域字符串很麻烦,尤其是当区域为许多不连续单元格区域组成时。这时可按住Ctrl键,进行不连续区域的选取。区域选定后选择“插入”\“名字”\“定义”,将此区域命名,如Group1,然后在公式中使用这个区域名,如“=SUM(Group1)”。

      40、如何定义局部名字?

       在默认情况下,工作薄中的所有名字都是全局的。其实,可以定义局部名字,使之只对某个工作表有效,方法是将名字命名为“工作表名!名字”的形式即可。

      41、如何命名常数?

       有时,为常数指定一个名字可以节省在整个工作簿中修改替换此常数的时间。例如,在某个工作表中经常需用利率4.9%来计算利息,可以选择“插入”\“名字”\“定 义”,在“当前工作薄的名字”框内输入“利率”,在“引用位置”框中输入“= 0.04.9”,按“确定”按钮。

      42、工作表名称中能含有空格吗?

       能。例如,你可以将某工作表命名为“Zhu Meng”。有一点结注意的是,当你在其他工作表中调用该工作表中的数据时,不能使用类似“= ZhU Meng!A2”的公式,否则 Excel将提示错误信息“找不到文件Meng”。解决的方法是,将调用公式改为“='Zhu Mg'! A2”就行了。当然,输入公式时,你最好养成这样的习惯,即在输入“=”号以后,用鼠标单由 Zhu Meng工作表,再输入余下的内容。

      43、给工作表命名应注意的问题

       有时为了直观,往往要给工作表重命名(Excel默认的荼表名是sheet1、sheet2.....),在重命名时应注意最好不要用已存在的函数名来作荼表名,否则在下述情况下将产征收岂义。我们知道,在工作薄中复制工作表的方法是,按住Ctrl健并沿着标签行拖动选中的工作表到达新的位置,复制成的工作表以“源工作表的名字+(2)”形式命名。例如,源表为ZM,则其“克隆”表为ZM(2)。在公式中Excel会把ZM(2)作为函数来处理,从而出错。因而应给ZM(2)工作表重起个名字。

      44、如何拆分或取消拆分窗口?

       当我们给一个工作表输入数据时,在向下滚动过程中,尤其是当标题行消失后,有时会记错各列标题的相对位置。这时可以将窗口拆分为几部分,然后将标题部分保留在屏幕上不动,只滚动数据部分。其方法是在主菜单上单击“窗口”\“拆分窗口”。取消拆分窗口时除了使用“窗口”\“撒消拆分窗口”命令外,有捷径:将鼠标指针置于水平拆分或垂直拆分线或双拆分钱交点上,双击鼠标即可取消已拆分的窗口。

      45、如何给工作簿扩容?

       选取“工具”\“选项”命令,选择“常规”项,在“新工作薄内的工作表数”对话栏用上下箭头改变打开新工作表数。一个工作薄最多可以有255张工作表,系统默认值为6。

      46、如何减少重复劳动?

       我们在实际应用Excel时,经常遇到有些操作重复应用(如定义上下标等)。为了减少重复劳动,我们可以把一些常用到的操作定义成宏。其方法是:选取“工具”菜单中的“宏”命令,执行“记录新宏”,记录好后按“停止”按钮即可。也可以用VBA编程定义宏。

      47、如何快速地批量修改数据?

       假如有一份 Excel工作簿,里面有所有职工工资表。现在想将所有职工的补贴增加50(元),当然你可以用公式进行计算,但除此之外还有更简单的批量修改的方法,即使用“选择性粘贴”功能: 首先在某个空白单元格中输入50,选定此单元格,选择“编辑”\“复制”。选取想修改的单元格区域,例如从E2到E150。然后选择“编辑”\“选择性粘贴”,在“选择性粘贴”对话框“运算”栏中选中“加”运算,按“确定”健即可。最后,要删除开始时在某个空白单元格中输入的50。

      48、如何快速删除特定的数据?

       假如有一份Excel工作薄,其中有大量的产品单价、数量和金额。如果想将所有数量为0的行删除,首先选定区域(包括标题行),然后选择“数据”\“筛选”\“自动筛选”。在“数量”列下拉列表中选择“0”,那么将列出所有数量为0的行。此时在所有行都被选中的情况下,选择“编辑”\“删除行”,然后按“确定”即可删除所有数量为0的行。最后,取消自动筛选。

      49、如何快速删除工作表中的空行?

       以下几种方法可以快速删除空行:

       方法一:如果行的顺序无关紧要,则可以根据某一列排序,然后可以方便地删掉空行。

       方法二:如果行的顺序不可改变,你可以先选择“插入”\“列”,插入新的一列入在A列中顺序填入整数。然后根据其他任何一列将表中的行排序,使所有空行都集中到表的底部,删去所有空行。最后以A列重新排序,再删去A列,恢复工作表各行原来的顺序。

       方法三:使用上例“如何快速删除特定的数据”的方法,只不过在所有列的下拉列表中都选择“空白”。

      50、如何使用数组公式?

       Excel中数组公式非常有用,它可建立产生多值或对一组值而不是单个值进行操作的公式。要输入数组公式,首先必须选择用来存放结果的单元格区域,在编辑栏输入公式,然后按ctrl+Shift+Enter组合键锁定数组公式,Excel将在公式两边自动加上括号“{}”。不要自己键入花括号,否则,Excel认为输入的是一个正文标签。要编辑或清除数组公式.需选择数组区域并且激活编辑栏,公式两边的括号将消失,然后编辑或清除公式,最后按Ctrl+shift+Enter键。

      51、如何不使显示或打印出来的表格中包含有0值?

       通常情况下,我们不希望显示或打印出来的表格中包含有0值,而是将其内容置为空。例如,图1合计列中如果使用“=b2+c2+d2”公式,将有可能出现0值的情况,如何让0值不显示? 方法一;使用加上If函数判断值是否为0的公式,即: =if(b2+c2+d2=0,“”, b2+c2+d2) 方法二:选择“工具”\“选项”\“视窗”,在“窗口选项”中去掉“零值”选项。 方法三:使用自定义格式。 选中 E2:E5区域,选择“格式”\“单元格”\“数字”,从“分类”列表框中选择“自定义”,在“格式”框中输入“G/通用格式;G/通用格式;;”,按“确定”按钮即可。

      52、在Excel中用Average函数计算单元格的平均值的,值为0的单元格也包含在内。有没有办法在计算平均值时排除值为0的单元格?

       方法一:如果单元格中的值为0,可用上例“0值不显示的方法”将其内容置为空,此时空单元格处理成文本,这样就可以直接用Average函数计算了。

       方法二:巧用Countif函数 例如,下面的公式可计算出b2:B10区域中非0单元格的平均值:

      =sum(b2: b10)/countif(b2: b1o,"<>0")

      53、如何在Excel中实现“自动更正”功能?

       Word用户都知道,利用Word的“自动更正”功能可以实现数据的快速输入.但在Excel中却没有类似“自动更正”功能的菜单命令。其实,使用VloopuP函数可以巧妙地解决这一问题 (转载)

  • 掌握有效测试软件的方法与技术(转)

    2007-03-30 10:24:48

    1. 测试的常识与道理
    1.1 你真的懂测试吗
    u 编程大师说:没有错误的程序世间难求。 (《编程之道》)
    u 你在学校里学过测试吗?(读到博士可能也不懂测试)
    u 你所在的企业重视测试吗? (小公司程序员的技能更加全面)
    u 临时抱佛脚行吗?你以为有文档模板就会测试了吗?
    u 如果不懂得有效地进行测试,你不仅得不到功劳,也没人欣赏你的苦劳,你拥有最多的将只是疲劳。
    u 职业软件工程师应当掌握需求开发、系统设计、编程、测试、维护 所有技能。

    1.2 测试的目的是什么

    u 测试的目的是为了发现尽可能多的缺陷,不是为了说明软件中没有缺陷。
    u 推论:成功的测试在于发现了迄今尚未发现的缺陷。所以测试人员的职责是设计这样的测试用例,它能有效地揭示潜伏在软件里的缺陷。
    u 千万不要将“测试”与“演示”混为一谈。例如科研鉴定会。
    u 如果产品通过了严格的测试,大家不要不吭气,应当好好地宣传一把 。

    1.3 一些常识和经验之谈

    u 测试能提高软件的质量,但是提高质量不能依赖测试。
    u 测试只能证明缺陷存在,不能证明缺陷不存在。“彻底地测试”难以成为现实,要考虑时间、费用等限制,不允许无休止地测试。我们应当祈祷:软件的缺陷在产品被淘汰之前一直没有机会发作。
    u 测试的主要困难是不知道如何进行有效地测试,也不知道什么时候可以放心地结束测试。
    u 每个开发人员应当测试自己的程序(份内之事),但是不能作为该程序已经通过测试的依据(所以项目需要独立测试人员)。
    u 80-20原则:80%的缺陷聚集在20%的模块中,经常出错的模块改错后还会经常出错
    u 测试应当循序渐进,不要企图一次性干完,注意“欲速则不达”。

    2. 测试的分类与比较


    u 问题1:有了“黑盒”测试为什么还要“白盒”测试?
    – 黑盒测试只能观察软件的外部表现,即使软件的输入输出都是正确的,却并不能说明软件就是正确的。因为程序有可能用错误的运算方式得出正确的结果,例如“负负得正,错错得对”,只有白盒测试才能发现真正的原因。

    – 白盒测试能发现程序里的隐患,象内存泄漏、误差累计问题。在这方面,黑盒测试存在严重的不足。
    u 问题2:由于单元测试要写测试驱动程序,非常麻烦,能否等到整个系统全部开发完后,再集中精力进行一次性地单元测试呢?

    – 如果这样做,在开发过程中,缺陷会越积越多并且分布得更广、隐藏得更深,反而导致测试与改错的代价大大增加。最糟糕的是无法估计测试与改错的工作量,使进度失去控制。因此为图眼前省事而省略单元测试或者“偷工减料”,是“得不偿失”的做法。
    u 问题3:如果每个单元都通过了测试,把它们集成一起难道会有什么不妥吗?集成测试是否多此一举?

    – 要把N个单元集成一起肯定靠接口耦合,这时可能会产生在单元测试中无法发现的问题。例如:数据通过不同的接口时可能出错;几个函数关联在一起时可能达不到 预期的功能;在某个单元里可以接受的误差可能在集成后被扩大到无法接受的程度。所以集成测试是必要的,不是多此一举。

    u 问题4:在集成测试的时候,已经对一些子系统进行了功能测试、性能测试等等,那么在系统测试时能否跳过相同内容的测试?

    – 不能!因为集成测试是在仿真环境中开展的,那不是真正的目标系统。再者,单元测试和集成测试通常由开发小组执行。根据测试心理学的分析,开发人员测试自己的工作成果虽然是必要的,但不能作为成果已经通过测试的依据。

    u 问题5:既然系统测试与验收测试的内容几乎是相同的,为什么还要验收测试?
    – 首先是“信任”问题。对于合同项目而言,如果测试小组是开发方的人员,客户怎么能够轻易相信“别人”呢? 所以当项目进行系统测试之后,客户再进行验收测试是情理之中的事。否则,那是客户失职。

    – 不论是合同项目还是非合同项目,软件的最终用户各色各样(如受教育程度不同、使用习惯不同等等)。测试小组至多能够模仿小部分用户的行为,但并不具有普遍的代表性。

    u 问题6:能否将系统测试和验收测试“合二为一”?

    – 系统测试不是一会儿就能做完的,比较长时间的用户测试很难组织。用户还有自己的事情要做,他们为什么要为别人测试呢?即使用户愿意做系统测试,他们消耗的时间、花费的金钱大多比测试小组的高。

    – 系统测试时会找出相当多的软件缺陷,软件需要反反复复地改错。如果让用户发现“内幕”,一是丢脸,二是会吓跑买主。所以还是关起门来,先让测试小组做完系统测试的好。

    3. 测试人员的组织

    3.1 了解开发人员的测试心理

    u 测试的目的是找出尽可能多的缺陷。所以测试是“破坏性”的,而开发却是“建设性”的。开发人员总是喜欢欣赏程序的成功之处,而不愿看到失败之处。让开发者去做“蓄意破坏”的测试,就象杀自己的孩子一样难以接受。

    u 开发者对自己的程序印象深刻,并总以为是正确的(自信是应该的)。倘若在设计时就存在理解错误,或因不良的编程习惯而流下了隐患,他本人很难发现这类错误.

    u 开发者对自己的程序的功能、接口十分熟悉,他自己几乎不可能因为使用不当而引发错误,这与大众用户的情况不太相似,所以测试自己的程序不具备典型性。

    u 结论:开发人员应当测试自己的程序,这是他分内的工作。但是开发人员在测试自己的程序时,很难做到客观、公正,所以自我测试不具有说服力。

    3.2 如何组织测试人员:应当视企业的人力资源而定

    u 条件特别好的公司,可以为每一个开发人员分配一名独立的测试人员。这样的测试人员职业化程度很高,可以完成单元测试、集成测试和系统测试工作,能够实现开发与测试同步进行。

    u 条件比较好的公司,可以设置一个独立的测试小组,该测试小组轮流参加各个项目的系统测试。而单元测试、集成测试工作由项目的开发小组承担。

    u 条件一般的公司,养不起独立的测试小组。单元测试、集成测试工作由项目开发小组承担。当项目进展到系统测试阶段,可以从项目外抽调一些人员,加上开发人员,临时组织系统测试小组。

    u 条件比较差的公司,也许只有一个项目和为数不多的一些开发人员。那么就让开发人员一直兼任测试人员的角色,相互测试对方的程序。如果人员实在太少了,只好让开发者测试自己的程序,有测试总比没有测试好吧!

    3.3 避免开发人员与测试人员产生矛盾

    u 开发人员的注意事项:

    不要敌视测试人员。要理解测试的目的就是发现缺陷,是测试人员的工作职责。不要以为测试人员吃饱了没事干,存心找茬。

    不要轻视测试人员,别说人家技术水平差,不配搞开发只好搞测试。

    u 测试人员的注意事项:

    发现缺陷时不要嘲笑开发人员,别说他的程序真臭、到处是Bug。

    在开发人员压力太大时或心情不好时不要火上浇油,发现缺陷时别大声嚷嚷。

    u 请留意另一种极端:如果测试人员与开发人员的关系非常好,可能会导致在测试的时候“手下留情”,这对项目也是一种伤害。

    4. 企业的测试策略
    4.1 理念:
    u 企业的主要目的是获取利润,降低测试成本也是盈利的一种方式。
    u 用较低的代价实现有效的测试,不应为了追求完美的测试而不失一切代价。
    4.2 如何合理地减少测试工作量
    u 减少冗余的测试
    白盒测试与黑盒测试的方式虽然不同,但往往有“异曲同工”之妙。在很多地方,白盒测试与黑盒测试会产生一模一样的效果(或者能推理出来),这样的测试是冗余的。
    在集成测试、系统测试阶段,可能要执行多次“回归测试”。每一次“回归测试”都会存在不少的冗余,应当设法剔除不必要的重复测试工作。
    u 减少无价值的测试
    无价值的测试通常是由于不懂得测试技术引起的。例如功能测试,在等价区间之中,本来只要测试一个典型的输入就行了,如果有人在此区间测试了100次,那么其中99次就是无价值的。
    u 如何“偷工减料”
    有 一些“短、平、快”的项目,经费本来就少,用户对质量要求也马马虎虎。为了能多挣一点钱,开发方不得不采用“偷工减料”的方式来降低测试代价。偷工减料的 途径无非就是减少测试的内容和频度。但不能砍得太狠,否则软件拿不出手。基本方法是找出软件中需要优先测试的部分(见下表),其它次要部分可以忽略或将来 再测试。
    u “偷工减料”方法的测试优先级:
    哪些功能是软件的特色?
    哪些功能是用户最常用的?
    如果系统可以分块卖的话,哪些功能块在销售时最昂贵?
    哪些功能出错将导致用户不满或索赔?
    哪些程序是最复杂、最容易出错的?
    哪些程序是相对独立,应当提前测试的?
    哪些程序最容易扩散错误?
    哪些程序是全系统的性能瓶颈所在?
    哪些程序是开发者最没有信心的?
    4.3 测试何时结束
    u 基于测试用例的规则
    u 基于“测试期缺陷密度”的规则
    u 基于“运行期缺陷密度”的规则
    4.4 测试奖励机制
    u 根据缺陷的危害程度,把奖金分等级。每个新缺陷对应一份奖金,把奖金发给第一个发现该缺陷的人。奖金额要适当,太低了人们不感兴趣,太高了会让项目破产的。

    5. 测试规范
    5.1 测试流程
    u 第一步:制定测试计划。该计划被批准后转向第二步。
    u 第二步:设计测试用例。该用例被批准后转向第三步。
    u 第三步:如果满足“启动准则” ,那么执行测试。
    u 第四步:撰写测试报告。
    u 第五步:消除软件缺陷。如果满足“完成准则”,那么正常结束测试。
    5.2 测试启动准则
    u 同时满足以下条件,允许开始测试:
    (1)测试计划已经制定并且通过了审批;
    (2)测试用例已经设计并且通过了审批;
    (3)被测试对象已经开发完毕并等待测试。
    5.3 测试完成准则
    u 对于非严格系统可以采用“基于测试用例”的准则。同时满足以下条件允许结束测试:
    (1)功能性测试用例通过率达到100%;
    (2)非功能性测试用例通过率达到90%时。
    u 对于严格系统,应当补充“基于测试期缺陷密度”的规则:
    (3)相邻n个CPU小时内“测试期缺陷密度”全部低于某个值m。例如n大于10,m小于等于1。
    6. 软件系统的主要测试内容及技术
    6.1 接口与路径测试
    u 数据一般通过接口输入和输出,所以接口测试是白盒测试的第一步。每个接口可能有多个输入参数,每个参数有“典型值”、“边界值”、“异常值”之分,所以输 入的组合数可能并不少。根据接口的定义,可以推断某种输入应当产生什么样的输出。输出包括函数的返回值和输出参数。如果实际输出与期望的输出不一致,那么 说明程序有错误。白盒方式的接口测试和黑盒方式的功能测试,其方法十分相似。
    u 一个函数体内的语句可能只有十几条,但逻辑路径可能有成千上万条。想遍历测试几乎是不可能的,不测试或者胡乱找几条路径测试却又不行。
    u 对于非严格系统而言,在分析路径方面化费很多精力是不值得的。我认为在构造接口测试的同时已经建立了测试路径。因为每一种输入将产生唯一的输出,输入与输 出之间的路径也是唯一的。由于接口测试中的输入是有代表性的,因此相应的路径也具有代表性,不用得着费煞苦心地去找测试路径。
    u 路径测试的检查表
    数据类型、变量值、逻辑判断、循环、内存管理、文件I/O、错误处理
    u 由于接口测试是枚举的,有可能漏掉某些状况,导致一些重要的路径没有被测试。预防措施有:
    观察是否有程序语句从来没有被执行过。如果发生在这种情况,要么是程序有错误,存在无用的代码;要么是接口测试不充分,漏掉了一些路径。
    要特别留意函数体内的错误处理程序块(如果存在的话),这是最易被人疏忽的路径,隐患最多。

    6.2 功能测试
    u 功能测试的基本方法是构造一些合理输入(在需求范围之内),检查输出是否与期望的相同。如果两者不一致,即表明功能有误。也有例外的情况,如《需求规格说明书》中的某个功能写错了,而实际上软件的功能却是正确的,这时要更改的是《需求规格说明书》。
    u 功能测试看起来比较简单,只要看得懂《需求规格说明书》,谁都会做。难点在于如何构造有效的输入。由于输入空间通常是无限的,穷举测试显然行不通。那么随便输入一些东西,碰运气行不行?
    u 功能测试有两种比较好的测试方法:等价划分法和边界值分析法。
    等价划分是指把输入空间划分为几个“等价区间”,在每个“等价区间”中只需要测试一个典型值就可以了。等价划分法来源于人们的直觉与经验,可令测试事半功倍。
    “缺陷遗漏在角落里,聚集在边界上”。边界值测试法是对等价划分法的补充。如果A和B是输入空间的边界值,那么除了典型值外还要用A和B作为测试用例。
    例如测试函数。凭直觉,等价区间应是(0, 1)和(1, +∞)。可取典型值x=0.5以及x=2.0进行“等价划分”测试。再取 x=0以及x=1进行“边界值”测试。
    6.3 健壮性测试
    u 健壮性是指在异常情况下,软件还能正常运行的能力。健壮性有两层含义:一是容错能力,二是恢复能力。
    u 容错性测试通常构造一些不合理的输入来引诱软件出错,例如:
    (1)输入错误的数据类型。如“猴”年“马”月。
    (2)输入定义域之外的数值。如上海人常说的“十三点”
    u 粗暴一些方式俗称“大猩猩”测试法。除了不能拳打脚踢嘴咬外,什么招术都可以使出来。例如在测试客户机-服务器模式的软件时,把网络线拔掉,造成通信异常中断。
    u 恢复测试重点考察一下几项:
    (1)系统能否重新运行;
    (2)有无重要的数据丢失;
    (3)是否毁坏了其它相关的软件硬件。
    6.4 性能测试
    u 性能测试即测试软件处理事务的速度,一是为了检验性能是否符合需求,二是为了得到某些性能数据供人们参考(例如用于宣传)。
    u 有时人们关心测试的“绝对值”,如数据送输速率是每秒多少比特。有时人们关心测试的“相对值”,如某个软件比另一个软件快多少倍。
    u 在获取测试的“绝对值”时,我们要充分考虑并记录运行环境对测试的影响。例如网络环境、计算机主频,总线结构和外部设备都可能影响软件的运行速度。
    u 性能测试的一些注意事项:
    不要试图让人拿着钟表去测时间,应当编写一段程序用于计算时间以及相关数据。
    应当测试软件在标准配置和最低配置下的性能。
    为了排除干扰,应当关闭那些消耗内存、占用CPU的其它应用软件(如杀毒软件)。
    不同的输入情况会得到不同的性能数据,应当分档记录。例如传输文件的容量从100K到1M可以分成若干等级。
    由于环境的波动,同一种输入情况在不同的时间可能得到不同的性能数据,可以取其平均值。
    6.5 用户界面测试
    u 绝大多数软件拥有图形用户界面。图形用户界面的测试重点是正确性、易用性和视觉效果。在评价易用性和视觉效果时,主观性非常强,应当考虑多个人的观点。
    6.6 信息安全测试
    u 信息安全性(security)是指防止系统被非法入侵的能力,既属于技术问题又属于管理问题。
    u 信息安全性测试有如下步骤:
    (1)为非法入侵设立目标,例如“盗窃某个文件”或“更改数据库记录”等。
    (2)邀请(或悬赏)一些人扮演黑客,让他们想尽办法入侵系统,实现“目标”。
    (3)如果有人成功了,请他详述入侵的过程。别忘了给予奖励。
    6.7 压力测试
    u 压力测试也叫负荷测试,即获取系统能正常运行的极限状态。了解“极限”是很有价值的,例如潜艇下潜极限深度…。
    u 压力测试的主要任务是:构造正确的输入,使劲折腾系统却让它刚好不瘫痪。
    u 压力测试的一个变种是敏感测试。在某种情况下,微小的输入变动会导致系统的表现(如性能)发生急剧的变化。敏感测试目的是发现什么样的输入可能会引发不稳定现象。
    6.8 可靠性测试
    u 可靠性是指在一定的环境下、在给定的时间内、系统不发生故障的概率。由于软件不像硬件那样可以“加速老化”,按此定义,软件可靠性测试可能会花费很长时间。
    u 比较实用的办法是,让用户使用该系统,记录每一次发生故障的时刻。计算出相邻故障的时间间隔,注意要去掉非工作时间。这样我们可以方便地统计出不发生故障 的“最小时间间隔”、“最大时间间隔”和“平均时间间隔”。其中“平均时间间隔”会让人们大体了解到系统“可靠”的程度。
    6.9 安装 / 反安装测试
    u 安装 / 反安装测试的目的:避免“大风浪都挺过来了,却在阴沟里翻了船”
    u 目前市面上有非常流行的、专门制作安装/反安装程序的一些工具,如Install Shelled。制作安装/反安装程序不再是件难事,关键是不要麻痹大意。主要测试工作:
    (1)至少在标准配置和最低配置两种环境下测试;
    (2)如果有安装界面,应当尝试各种选项,如选择“全部”、“部分”、“升级”等。

  • QTP识别和操作对象的原理(转载)

    2007-03-29 15:00:32

    一.QTP识别对象的原理

    QTP要求先在仓库文件里定义仓库对象,里面存有实际对象的特征属性的值,
    运行的时候,QTP会根据仓库对象的特征属性描述,寻找到实际对象,然后操作实际对象。

    仓库对象TO一般在录制/编写脚本时加入仓库文件,它不仅可以在编写时进行修改,
    也可以在运行过程中进行动态修改,以匹配实际对象。

    相关的几个函数有:

    GetTOProperty():取得仓库对象的某个属性的值
    GetTOProperties():取得仓库对象的所有属性的值
    SetTOProperty():设置仓库对象的某个属性的值

    GetROProperty():取得实际对象的某个属性的值


    理解了TO的含义,你就可以自由的用SetTOProperty()定义TO,以灵活的操作RO

    比如有个测试任务,窗口上有很多待检查的记录,每条记录右边都有一个Check按钮,用来检查各条记录。
    记录个数不定,所以Check按钮个数也就不定,只有一个Edit显示记录个数。
    我们要对每条记录进行检查,也就是要点击每个Check按钮。
    但是Check按钮个数不定,不好录制,而且个数可能也很多(上百个),即使能一一录制,那也很麻烦。

    那我有一个好办法,只录制一个按钮对象,它设有两个特征属性 label=OK, index=0
    然后用下面的脚本,就可以完成测试

    buttonNum = CInt(JavaWindow("Test").JavaEdit("Record Num").GetROProperty("value"))
    For buttonIndex = 0 to buttonNum - 1
      JavaWindow("Test").JavaButton("Check").SetTOProperty("index", buttonIndex)
      JavaWindow("Test").JavaButton("Check").Click
    Next


    或者窗口上有New、Modify、Delete、Check等好几个按钮,要把这几个按钮一一按过去
    我在对象仓库里只设置一个按钮对象AnyButton,label特征属性值填任意值,然后用下面脚本执行测试

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "New")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Modify")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Delete")
    JavaWindow("Test").JavaButton("AnyButton").Click

    JavaWindow("Test").JavaButton("AnyButton").SetTOProperty("label", "Check")
    JavaWindow("Test").JavaButton("AnyButton").Click


    另外,QTP还支持脚本描述的方法来定义和访问对象,即不需要在仓库里定义,也能访问和操作实际对象

    如上面两个任务,可以如下实现

    1. 不需要在仓库里定义Check按钮对象,直接用下面脚本来实现测试

    buttonNum = CInt(JavaWindow("Test").JavaEdit("Record Num").GetROProperty("value"))
    For buttonIndex = 0 to buttonNum - 1
      JavaWindow("Test").JavaButton("label:=Check", "index:="+CStr(buttonIndex)).Click
    Next

    2. 不需要在仓库里定义New、Modify、Delete、Check按钮对象,直接用下面脚本来实现测试

    JavaWindow("Test").JavaButton("label:=New").Click
    JavaWindow("Test").JavaButton("label:=Modify").Click
    JavaWindow("Test").JavaButton("label:=Delete").Click
    JavaWindow("Test").JavaButton("label:=Check").Click

    二.操作对象的原理

    QTP为用户提供了两种操作对象的接口,一种就是对象的封装接口,另一种是对象的自身接口。
    对象的自身接口是对象控件本身的接口,只要做过软件开发,使用过控件的人应该很清楚。
    对象的封装接口是QTP为对象封装的另一层接口,它是QTP通过调用对象的自身接口来实现的。


    两种接口的脚本书写格式的差别在于:
      自身接口需要在对象名后面加object再加属性名或方法名,
      封装接口就不用在对象名后面加object。

    比如操作JavaEdit对象,通过QTP封装的封装接口,脚本如下:
      设置JavaEdit的内容:
         JavaDialog("Add NE").JavaEdit("NE Name").Set "NE1"
      读取JavaEdit的内容:
         msgbox JavaDialog("Add NE").JavaEdit("NE Name").GetROProperty("value")

    如果通过JavaEdit的自身接口,脚本如下:
      设置JavaEdit的内容:
         JavaDialog("Add NE").JavaEdit("NE Name").object.setText("NE1")
      读取JavaEdit的内容:
         Msgbox JavaDialog("Add NE").JavaEdit("NE Name").object.getText()

    QTP执行JavaEdit().Set语句时,是通过执行JavaEdit().object.setText()来实现的。
    QTP执行JavaEdit().GetROProperty("value"),是通过执行JavaEdit().object.getText()来实现的。
    JavaEdit对象的封装接口Set()和GetROProperty("value"),是QTP封装JavaEdit对象的自身接口setText()和getText()而得来的。

    对象的封装接口是QTP使用的缺省接口,我们录制出来的脚本都是使用封装接口,大家用的也都是封装接口。
    但是封装接口不如自身接口丰富,因为QTP只是封装了部分常用的自身接口嘛。
    所以我们在需要时,可以绕过封装接口,直接调用对象的自身接口。
    不过有些自身接口不够稳定,在实践中偶尔会出现问题,但是概率很少。
    封装接口有相应功能的话,就尽量用封装接口吧!


    理解了封装接口和自身接口的原理,我们就可以更加灵活的操作对象了。

    但是我们怎么知道对象都有哪些封装接口和自身接口呢?
    其实很简单,用对象查看器(Object Spy)查看对象,在查看窗口里有列出这些接口,包括属性和方法。
    窗口中间有选择栏让你选择Run-time Object或者Test Object,
    当你选择Run-time Object时,它显示的就是对象的自身接口(自身的属性和方法)
    当你选择Test Object时,它显示的就是对象的封装接口(封装的属性和方法)

    明白了这些,你还等什么呢?快拿起对象查看器,看看对象都有哪些封装接口和自身接口,肆意的操作它,玩弄它吧!

    原始链接:http://bbs.51testing.com/thread-13554-1-1.html

  • 每日英文翻译2

    2007-03-27 23:49:19

    Simple design. Simple design has two parts. One, design for the functionality that has been defined, not for potential future functionality. Two, create the best design that can deliver that functionality. In other words, don't guess about the future: create the best (simple) design you can today. "If you believe that the future is uncertain, and you believe that you can cheaply change your mind, then putting in functionality on speculation is crazy," writes Beck. "Put in what you need when you need it."

     

     

    简单的设计,简单的设计包括两个方面:第一设计已经定义好的功能,而不是为潜在的功能设计,第二构思最能传递功能的设计,换句话说,不要猜测未来的功能;创建当前最好的简单的设计,如果你确信未来是不确定的,同时你也确信你可以很轻易地改变你的思想,那么把功能描述的很清楚是很具有冒险性的,beck这样写道,当你需要它的时候再描述它。

     

    标准译文

    简单的设计:简单的设计包含两个部分。一,为已定义的功能进行设计,而不是为潜在地未来可能的功能进行设计。二,创建最佳的可以实现功能的设计。换句话说,不用管未来会是怎样,只创建一个目前为止可以实现的最好的设计。"如果你相信未来是不确定的,并且你相信你可以很方便的改变你的主意的话,那么对未来功能的考虑是危险的。"Beck写到。"只有在你真正需要的时候才去做"

    Potential             adj.潜在的, 可能的 cheaply 便宜地

    speculation n.思索, 做投机买卖  

    putting in v.放进, 提出, 提交, 插入, 进入, 使就职, 种植, 进港

     

  • 每日英文翻译

    2007-03-26 23:20:05

    节选自极限编程

    英文原文

    Metaphor. XP's use of the terms "metaphor" and "story" take a little wearing in to become comfortable. However, both terms help make the technology more understandable in human terms, especially to clients. At one level, metaphor and architecture are synonyms -- they are both intended to provide a broad view of the project's goal. But architectures often get bogged down in symbols and connections. XP uses "metaphor" in an attempt to define an overall coherent theme to which both developers and business clients can relate. The metaphor describes the broad sweep of the project, while stories are used to describe individual features.

    译文

    象征,xp为了变得舒适使用了比喻和描述,然而,两个项目使得在人类项目中的技术更加容易理解。尤其对客户来说,在某种层次看来,象征和架构是同步的-----它们都为项目的目标提供了一个广泛的视野。当是结构经常陷入机构之间的表示和联系。Xp使用了象征是为了定义所有一系列连贯的开发者和商务客户能够建立联系的主题。象征描述了一个项目广阔的范围。同时描述习惯用来描述每个独立的特性。

     

    标准译文

    XP"隐喻"以及"story"的使用可能会让人有一点不舒服。但是,这些术语的使用可以帮助我们以一种更人性化的方式加以理解,尤其是对客户而言。从某种程度上来说,隐喻同体系结构是同意语――他们都着重于从全局描述一个项目。但是体系结构经常会陷于符号与连接的泥潭。而XP使用"隐喻"定义一个从开发者到商业客户都可联系的全面一致的主题。隐喻用于描述项目全面的面貌,而Story用于描述个别具体的特征。

    呵呵 理解错了好多地方,不过每天进步一点点,以后我的英语会越来越好

    Fighting~~~~~~~~~~~

  • 软件测试人员能力的基本要求(转)

    2007-03-26 10:55:38

    今天在测试群中看到有关能力的交流,大有裨益。
    TPfyB37286有些人片面的认为对测试人员而言,提高能力就是能写代码,而静光关于能力的深刻理解得到了大家的赞同。
    Z!@^N MX^37286下面原文引用:
    5L\g:E�S(b(m37286写代码,更多只算技术,未必是能力。
    #{)@%OZ bK#aA^6U3oX37286不要老想着写代码,如果一定要算能力,那也是很基本的能力。其它的能力实际上很多,你对计算机软硬件的了解,组成原理、电路逻辑等等各方面的知识,把这些知识归纳整理,在你平常的工作中应用出来,这就是能力。又比如,领导让你完成某个任务,你如何其了解领导真实的意图,了解任务相关的各种信息,找出其中的关键,再完成任务,这也是能力。1testing软件测试博客V’x$sn0e:lR”@M8[

    或者说,能力是多方面的,会写代码不代表能力就高,不会写代码不代表能力就低。只能说,对于你自己而言,你会写代码的时候,能力高于你不会写代码的时候。

    看到网上很多关于测试人员应具备的素质的文章,在这里想谈谈对测试人员能力的个人看法。
    _!^5EF(d$\,g d!}37286正如静光所言,能力是多方面的,我们对一个人能力的评价也应该是综合评价。51testing软件测试博客*qLO(N+It]
    能力包括基本能力、工作能力和专业技能等。51testing软件测试博客z6\V:uUU W7n
    基本能力包括沟通表达能力(归纳总结能力)、文档写作能力、学习能 力等;工作能力包括工作主动性、责任心、质量意识等,工作能力为以基本能力为基础,运用基本能力去解决工作上各种事情的能力;而我们经常谈到的代码编写、 自动化/性能测试工具的掌握,则属于专业技能等。因此专业技能并不能代表个人的综合能力。只有把专业技能和基本技能都掌握好并运用到工作中,才能较好的提 高我们的工作能力,体现出良好的综合能力。这3方面能力的关系如同木桶原理,哪方面低了这个桶的容水量都会大大折扣。在当今盛行自动化测试工具、性能测试工具学习之风,在提高专业能力的同时,请不用忽略了其它两方面的能力。

    再谈谈沟通表达能力中的归纳和总结能力,我觉得这个很重要。很多人在描述事情的时候讲了一大堆都没讲到点子上,流水帐式的,听者听得一塌糊涂,根本不知道在讲什么。同样论坛上很多人在提问题的时候也是如此。这就是缺乏归纳总结能力的问题所在。能否用提炼过的、总结性的文字描述你的问题,简单扼要,抓住重点,这也是一种能力。

    另外,工作能力中的质量意识经常被忽略,但我绝对这一点对测试人员非常重要。试想一下,作为一个与质量相关的测试人员,如果对自己的产出物质量要求 不高,编写的文档很多错别字,提交的缺陷描述缺少了必要的步骤描述,工作任务马虎应付得过且过,对自己没有高的质量要求又如何去要求开发人员产出高质量的 代码?51testing软件测试博客:K*s1j0V{ FO-Z.z2e

    转自:http://www.rickyzhu.com/2007/03/24/ablity-for-software-test-engineer/

  • 如何维持和提高我们的测试技能(转)

    2007-03-23 18:08:34

    Mike Kelly在他的blog(http://www.testingreflections.com/node/view/2723)中写了这篇文章,分享了他以及其他的几位测试工程师在IWST会议中讨论得出的一些成果,这里给大家把重点提一下,可以看看国外的测试同行是如何锻炼内功的,希望能有些许参考价值。
        通过五个方面的资源来维持和提高测试技能:
        1、网站
        www.Stickyminds.com
        www.Kaner.com
        www.Testingreflections.com
        www.jrothman.com
        www.PerfTestPlus.com
        2、书籍
        Lessons Learned in Software Testing by Kaner, Bach, and Pettichord
        Testing Computer Software by Kaner, Falk, and Nguyen
        Quality Software Management: Systems Thinking by Weinberg
        How to Break Software by Whittaker 
        Conjectures and Refutations: The Growth of Scientific Knowledge by Popper
        3、工具
        IBM的Rational工具和RUP
        Watir 和Ruby
        WebGoat 
        Logic Puzzles
        FireFox Web Developer
        4、团体
        software-testing邮件列表
        不同的本地讨论组,如QAI、RUG、JUG等
        Los Altos Style Workshops(注:老外很善于用workshop这种形式)
        Toastmasters
        Webgrrls International
        5、杂志
        Better Software
        Software Test and Performance
        CIO
        Fast Company
        Wired
        这里提到的这些资源,我有的使用过,有的则是连听都没听过。那我们是不是也可以思考一下我们中国的测试工程师都是通过什么资源来提高自己的测试技能呢?欢迎大家讨论。
  • 如何阅读源代码2(转)

    2007-03-23 17:48:28

    第一章:导论
    1. 要养成一个习惯,经常花时间阅读别人编写的高品质代码。
    2. 要有选择地阅读代码,同时,还要有自己的目标。您是想学习新的模式、编码风格、还是满足某些需求的方法?
    3. 要注意并重视代码中特殊的非功能性需求,这些需求也许会导致特定的实现风格。
    4. 在现有的代码上工作时,请与作者或维护人员进行必须的协调,以避免重复劳动或因此而产生厌恶情绪。
    5. 请将从开放源码软件中得到的益处看作是一项贷款,尽可能地寻找各种方式来回报开放源码社团。
    6. 多数情况下,如果您想要了解“别人会如何完成这个功能呢?”,除了阅读代码以外,没有更好的方法。
    7. 在寻找 BUG时,请从问题的表现形式到问题的根源来分析代码。不要沿着不相关的路径(误入岐途)
    8. 我们要充分利用调度器,编译器给出的警告或输出的符号代码,系统调用跟踪器,数据库结构化查询语言的日志机制、包转储工具和Windows的消息侦查程序,定出BUG的位置。
    9. 对于那些大型且组织良好的系统,您只需要最低限度地了解它的全部功能,就能够对它做出修改。
    10. 当向系统中增加新功能时,首先的任务就是找到实现类似特性的代码,将它作为待实现功能的模板。
    11. 从特性的功能描述到代码的实现,可以按照字符串消息,或使用关键词来搜索代码。
    12. 在移植代码或修改接口时, 您可以通过编译器直接定位出问题涉及的范围,从而减少代码阅读的工作量。
    13. 进行重构时,您从一个能够正常工作的系统开始做起,希望确保结束时系统能够正常工作。一套恰当的测试用例可以帮助您满足此项约束。
    14. 阅读代码寻找重构机会时,先从系统的构架开始,然后逐步细化,能够获得最大的效益。
    15. 代码的可重用性是一个诱人的,但难以掌握的思想;降低期望就不会感到失望。
    16. 如果您希望重要的代码十分棘手,难以理解与分离,可以试着寻找粒度更大一些的包,甚至其他代码。
    17. 在复查软件系统时,要注意,系统是由很多部分组成的,不仅仅只是执行语句。还要注意分析以下内容:文件和目录结构、生成和配置过程、用户界面和系统的文档。
    18. 可以将软件复查作为一个学习、讲授、援之以手和接受帮助的机会。

    第二章:基本编程元素
    19.第一次分析一个程序时, main是一个好的起始点.

    20.层叠if-else if-...-else序列可以看作是由互斥选择项组成的选择结构.

    21.有时, 要想了解程序在某一方面的功能, 运行它可能比阅读源代码更为恰当.

    22.在分析重要的程序时, 最好首先识别出重要的组成部分.

    23.了解局部的命名约定, 利用它们来猜测变量和函数的功能用途.

    24.当基于猜测修改代码时, 您应该设计能够验证最初假设的过程. 这个过程可能包括用编译器进行检查|引入断言|或者执行适当的测试用例.

    25.理解了代码的某一部分, 可能帮助你理解余下的代码.

    26.解决困难的代码要从容易的部分入手.

    27.要养成遇到库元素就去阅读相关文档的习惯; 这将会增强您阅读和编写代码的能力.

    28.代码阅读有许多可选择的策略: 自底向上和自顶向下的分析|应用试探法和检查注释和外部文档, 应该依据问题的需要尝试所有这些方法.

    29.for (i=0; i<n; i++)形式的循环执行n次; 其他任何形式都要小心.

    30.涉及两项不等测试(其中一项包括相等条件)的比较表达式可以看作是区间成员测试.

    31.我们经常可以将表达式应用在样本数据上, 借以了解它的含义.

    32.使用De Morgan法则简化复杂的逻辑表达式.

    33.在阅读逻辑乘表达式时, 问题可以认为正在分析的表达式以左的表达式均为true; 在阅读逻辑和表达式时, 类似地, 可以认为正在分析的表

    达式以左的表达式均为false.

    34.重新组织您控制的代码, 使之更为易读.

    35.将使用条件运行符? :的表达式理解为if代码.

    36.不需要为了效率, 牺牲代码的易读性.

    37.高效的算法和特殊的优化确实有可能使得代码更为复杂, 从而更难理解, 但这并不意味着使代码更为紧凑和不易读会提高它的效率.

    38.创造性的代码布局可以用来提高代码的易读性.

    39.我们可以使用空格|临时变量和括号提高表达式的易读性.

    40.在阅读您所控制的代码时, 要养成添加注释的习惯.

    41.我们可以用好的缩进以及对变量名称的明智选择, 提高编写欠佳的程序的易读性.

    42.用diff程序分析程序的修订历史时, 如果这段历史跨越了整体重新缩排, 常常可以通过指定-w选项, 让diff忽略空白差异, 避免由于更改了

    缩进层次而引入的噪音.

    43.do循环的循环体至少执行一次.

    44.执行算术运算时, 当b=2n-1时, 可以将a&b理解为a%(b+1).

    45.将a<<n理解为a*k, k=2n.

    46.将a>>n理解为a/k, k=2n.

    47.每次只分析一个控制结构, 将它的内容看作是一个黑盒.

    48.将每个控制结构的控制表达式看作是它所包含代码的断言.

    49.return, goto, break和continue语句, 还有异常, 都会影响结构化的执行流程. 由于这些语句一般都会终止或重新开始正在进行的循环,

    因此要单独推理它们的行为.

    50.用复杂循环的变式和不变式, 对循环进行推理.

    51.使用保持含义不变的变换重新安排代码, 简化代码的推理工作.

    第三章: 高级C数据类型
    52.了解特定语言构造所服务的功能之后, 就能够更好地理解使用它们的代码.

    53.识别并归类使用指针的理由.

    54.在C程序中, 指针一般用来构造链式数据结构|动态分配的数据结构|实现引用调用|访问和迭代数据元素|传递数组参数|引用函数|作为其他

    值的别名|代表字符串|以及直接访问系统内存.

    55.以引用传递的参数可以用来返回函数的结果, 或者避免参数复制带来的开销.

    56.指向数组元素地址的指针, 可以访问位于特定索引位置的元素.

    57.指向数组元素的指针和相应的数组索引, 作用在二者上的运算具有相同的语义.

    58.使用全局或static局部变量的函数大多数情况都不可重入(reentrant).

    59.字符指针不同于字符数组.

    60.识别和归类应用结构或共用体的每种理由.

    61.C语言中的结构将多个数据元素集合在一起, 使得它们可以作为一个整体来使用, 用来从函数中返回多个数据元素|构造链式数据结构|映射

    数据在硬件设备|网络链接和存储介质上的组织方式|实现抽象数据类型|以及以面向对象的方式编程.

    62.共用体在C程序中主要用于优化存储空间的利用|实现多态|以及访问数据不同的内部表达方式.

    63.一个指针, 在初始化为指向N个元素的存储空间之后, 就可以作为N个元素的数组来使用.

    64.动态分配的内在块可以电焊工地释放, 或在程序结束时释放, 或由垃圾回收器来完成回收; 在栈上分配的内存块当分配它的函数退出后释放

    .

    65.C程序使用typedef声明促进抽象, 并增强代码的易读性, 从而防范可移植性问题, 并模拟C++和Java的类声明行为.

    66.可以将typedef声明理解成变量定义: 变量的名称就是类型的名称; 变量的类型就是与该名称对应的类型.

    第四章: C数据结构
    67.根据底层的抽象数据类型理解显式的数据结构操作.

    68.C语言中, 一般使用内建的数组类型实现向量, 不再对底层实现进行抽象.

    69.N个元素的数组可以被序列for (i=0; i<N; i++)完全处理; 所有其他变体都应该引起警惕.

    70.表达式sizeof(x)总会得到用memset或memcpy处理数组x(不是指针)所需的正确字节数.

    71.区间一般用区间内的第一个元素和区间后的第一个元素来表示.

    72.不对称区间中元素的数目等于高位边界与低位边界的差.

    73.当不对称区间的高位边界等于低位边界时, 区间为空.

    74.不对称区间中的低位边界代表区间的第一个元素; 高位边界代表区间外的第一个元素.

    75.结构的数组常常表示由记录和字段组成的表.

    76.指向结构的指针常常表示访问底层记录和字段的游标.

    77.动态分配的矩阵一般存储为指向数组列的指针或指向元素指针的指针; 这两种类型都可以按照二维数组进行访问.

    78.以数组形式存储的动态分配矩阵, 用自定义访问函数定位它们的元素.

    79.抽象数据类型为底层实现元素的使用(或误用)方式提供一种信心的量度.

    80.数组用从0开始的顺序整数为键, 组织查找表.

    81.数组经常用来对控制结构进行高效编码, 简化程序的逻辑.

    82.通过在数组中每个位置存储一个数据元素和一个函数指针(指向处理数据元素的函数), 可以将代码与数据关联起来.

    83.数组可以通过存储供程序内的抽象机(abstract machine)或虚拟机(virtual machine)使用的数据或代码, 控制程序的运作.

    84.可以将表达式sizeof(x) / sizeof(x[0])理解为数组x中元素的个数.

    85.如果结构中含有指向结构自身|名为next的元素, 一般说来, 该结构定义的是单向链表的结点.

    86.指向链表结点的持久性(如全局|静态或在堆上分配)指针常常表示链表的头部.

    87.包含指向自身的next和prev指针的结构可能是双向链表的结点.

    88.理解复杂数据结构的指针操作可以将数据元素画为方框|指针画为箭头.

    89.递归数据结构经常用递归算法来处理.

    90.重要的数据结构操作算法一般用函数参数或模板参数来参数化.

    91.图的结点常常顺序地存储在数组中, 链接到链表中, 或通过图的边链接起来.

    92.图中的边一般不是隐式地通过指针, 就是显式地作为独立的结构来表示.

    93.图的边经常存储为动态分配的数组或链表, 在这两种情况下, 边都锚定在图的结点上.

    94.在无向图中, 表达数据时应该将所有的结点看作是等同的, 类似地, 进行处理任务的代码也不应该基于它们的方向来区分边.

    95.在非连通图中, 执行遍历代码应该能够接通孤立的子图.

    96.处理包含回路的图时, 遍历代码应该避免在处理图的回路进入循环.

    97.复杂的图结构中, 可能隐藏着其他类型的独立结构.

    第五章: 高级控制流程
    98.采用递归定义的算法和数据结构经常用递归的函数定义来实现.

    99.推理递归函数时, 要从基准落伍测试开始, 并认证每次递归调用如何逐渐接近非递归基准范例代码.

    100.简单的语言常常使用一系列遵循该语言语法结构的函数进行语法分析.

    101.推理互递归函数时, 要基于底层概念的递归定义.

    102.尾递归调用等同于一个回到函数开始处的循环.

    103.将throws子句从方法的定义中移除, 然后运行Java编译器对类的源代码进行编译, 就可以容易地找到那些可能隐式地生成异常的方法.

    104.在多处理器计算机上运行的代码常常围绕进程或线程进行组织.

    105.工作群并行模型用于在多个处理器间分配工作, 或者创建一个任务池, 然后将大量需要处理标准化的工作进行分配.

    106.基于线程的管理者/工人并行模型一般将耗时的或阻塞的操作分配给工人子任务, 从而维护中心任务的响应性.

    107.基于进程的管理者/工人并行模型一般用来重用现有的程序, 或用定义良好的接口组织和分离粗粒度的系统模块.

    108.基于流水线的并行处理中, 每个任务都接收到一些输入, 对它们进行一些处理, 并将生成的输出传递给下一个任务, 进行不同的处理.

    109.竞争条件很难捉摸, 相关的代码常常会将竞争条件扩散到多个函数或模块; 因而, 很难隔离由于竞争条件导致的问题.

    110.对于出现在信号处理器中的数据结构操作代码和库调用要保持高度警惕.

    111.在阅读包含宏的代码时, 要注意, 宏既非函数, 也非语句.

    112.do…while(0)块中的宏等同于控制块中的语句.

    113.宏可以访问在它的使用点可见的所有局部变量.

    114.宏调用可改变参数的值

    115.基于宏的标记拼接能够创建新的标记符.

    第六章: 应对大型项目
    116.我们可以通过浏览项目的源代码树—包含项目源代码的层次目录结构, 来分析一个项目的组织方式. 源码树常常能够反映出项目在构架和

    软件过程上的结构.

    117.应用程序的源代码树经常是该应用程序的部署结构的镜像.

    118.不要被庞大的源代码集合吓倒; 它们一般比小型的专门项目组织得更出色.

    119.当您首次接触一个大型项目时, 要花一些时间来熟悉项目的目录树结构.

    120.项目的源代码远不只是编译后可以获得可执行程序的计算机语言指令; 一个项目的源码树一般还包括规格说明|最终用户和开发人员文档|

    测试脚本|多媒体资源|编译工具|例子|本地化文件|修订历史|安装过程和许可信息.

    121.大型项目的编译过程一般声明性地借助依赖关系来说明. 依赖关系由工具程序, 如make及其派生程序, 转换成具体的编译行动.

    122.大型项目中, 制作文件常常由配置步骤动态地生成; 在分析制作文件之前, 需要先执行项目特定的配置.

    123.检查大型编译过程的各个步骤时, 可以使用make程序的-n开关进行预演.

    124.修订控制系统提供从储存库中获取源代码最新版本的方式.

    125.可以使用相关的命令, 显示可执行文件中的修订标识关键字, 从而将可执行文件与它的源代码匹配起来.

    126.使用修订日志中出现的bug跟踪系统内的编号, 可以在bug跟踪系统的数据库中找到有关的问题的说明.

    127.可以使用修订控制系统的版本储存库, 找出特定的变更是如何实现的.

    128.定制编译工具用在软件开发过程的许多方面, 包括配置|编译过程管理|代码的生成|测试和文档编制.

    129.程序的调试输出可以帮助我们理解程序控制流程和数据元素的关键部分.

    130.跟踪语句所在的地点一般也是算法运行的重要部分.

    131.可以用断言来检验算法运作的步骤|函数接收的参数|程序的控制流程|底层硬件的属性和测试用例的结果.

    132.可以使用对算法进行检验的断言来证实您对算法运作的理解, 或将它作为推理的起点.

    133.对函数参数和结果的断言经常记录了函数的前置条件和后置条件.

    134.我们可以将测试整个函数的断言作为每个给定函数的规格说明.

    135.测试用例可以部分地代替函数规格说明.

    136.可以使用测试用例的输入数据对源代码序列进行预演.

    第七章: 编码规范和约定
    137.了解了给定代码库所遵循的文件组织方式后, 就能更有效率地浏览它的源代码.

    138.阅读代码时, 首先要确保您的编辑器或优美打印程序的tab设置, 与代码遵循的风格规范一致.

    139.可以使用代码块的缩进, 快速地掌握代码的总体结构.

    140.对编排不一致的代码, 应该立即给予足够的警惕.

    141.分析代码时, 对标记为XXX, FIXME和TODO的代码序列要格外注意: 错误可能就潜伏在其中.

    142.常量使用大写字母命名, 单词用下划线分隔.

    143.在遵循Java编码规范的程序中, 包名(package name)总是从一个顶级的域名开始(例如, org, com), 类名和接口名由大写字母开始, 方法

    和变量名由小写字母开始.

    144.用户界面控件名称之前的匈牙利记法的前缀类型标记可以帮助我们确定它的作用.

    145.不同的编程规范对可移植构造的构成有不同的主张.

    146.在审查代码的可移植性, 或以某种给定的编码规范作为指南时, 要注意了解规范对可移植性需求的界定与限制.

    147.如果GUI功能都使用相应的编程结构来实现, 则通过代码审查可以轻易地验证给定用户界面的规格说明是否被正确地采用.

    148.了解项目编译过程的组织方式与自动化方式之后, 我们就能够快速地阅读与理解对应的编译规则.

    149.当检查系统的发布过程时, 常常可以将相应发行格式的需求作为基准.

    第八章: 文档
    150.阅读代码时, 应该尽可能地利用任何能够得到的文档.

    151.阅读一小时代码所得到的信息只不过相当于阅读一分钟文档.

    152.使用系统的规格说明文档, 了解所阅读代码的运行环境.

    153.软件需求规格说明是阅读和评估代码的基准.

    154.可以将系统的设计规格说明作为认知代码结构的路线图, 阅读具体代码的指引.

    155.测试规格说明文档为我们提供可以用来对代码进行预演的数据.

    156.在接触一个未知系统时, 功能性的描述和用户指南可以提供重要的背景信息,从而更好地理解阅读的代码所处的上下文.

    157.从用户参考手册中, 我们可以快速地获取, 应用程序在外观与逻辑上的背景知识, 从管理员手册中可以得知代码的接口|文件格式和错误消

    息的详细信息.

    158.利用文档可以快捷地获取系统的概况, 了解提供特定特性的代码.

    159.文档经常能够反映和提示出系统的底层结构.

    160.文档有助于理解复杂的算法和数据结构.

    161.算法的文字描述能够使不透明(晦涩, 难以理解)的代码变得可以理解.

    162.文档常常能够阐明源代码中标识符的含义.

    163.文档能够提供非功能性需求背后的理论基础.

    164.文档还会说明内部编程接口.

    165.由于文档很少像实际的程序代码那样进行测试, 并受人关注, 所以它常常可能存在错误|不完整或过时.

    166.文档也提供测试用例, 以及实际应用的例子.

    167.文档常常还会包括已知的实现问题或bug.

    168.环境中已知的缺点一般都会记录在源代码中.

    169.文档的变更能够标出那些故障点.

    170.对同一段源代码重复或互相冲突的更改, 常常表示存在根本性的设计缺陷, 从而使得维护人员需要用一系列的修补程序来修复.

    171.相似的修复应用到源代码的不同部分, 常常表示一种易犯的错误或疏忽, 它们同样可能会在其他地方存在.

    172.文档常常会提供不恰当的信息, 误导我们对源代码的理解.

    173.要警惕那些未归档的特性: 将每个实例归类为合理|疏忽或有害, 相应地决定是否应该修复代码或文档.

    174.有时, 文档在描述系统时, 并非按照已完成的实现, 而是系统应该的样子或将来的实现.

    175.在源代码文档中, 单词gork的意思一般是指”理解”.

    176.如果未知的或特殊用法的单词阻碍了对代码的理解, 可以试着在文档的术语表(如果存在的话)|New Hacker’s Dictionary[Ray96]|或在

    Web搜索引擎中查找它们.

    177.总是要以批判的态度来看待文档, 注意非传统的来源, 比如注释|标准|出版物|测试用例|邮件列表|新闻组|修订日志|问题跟踪数据库|营

    销材料|源代码本身.

    178.总是要以批判的态度来看待文档; 由于文档永远不会执行, 对文档的测试和正式复查也很少达到对代码的同样水平, 所以文档常常会误导

    读者, 或者完全错误.

    179.对于那些有缺陷的代码, 我们可以从中推断出它的真实意图.

    180.在阅读大型系统的文档时, 首先要熟悉文档的总体结构和约定.

    181.在对付体积庞大的文档时, 可以使用工具, 或将文本输出到高品质输出设备上, 比如激光打印机, 来提高阅读的效率.

    第九章: 系统构架
    182.一个系统可以(在重大的系统中也确实如此)同时出多种不同的构架类型. 以不同的方式检查同一系统|分析系统的不同部分|或使用不同级

    别的分解, 都有可能发现不同的构架类型.

    183.协同式的应用程序, 或者需要协同访问共享信息或资源的半自治进程, 一般会采用集中式储存库构架.

    184.黑板系统使用集中式的储存库, 存储非结构化的键/值对, 作为大量不同代码元件之间的通信集线器.

    185.当处理过程可以建模|设计和实现成一系列的数据变换时, 常常会使用数据流(或管道—过滤器)构架.

    186.在批量进行自动数据处理的环境中, 经常会采用数据流构架, 在对数据工具提供大量支持的平台上尤其如此.

    187.数据流构架的一个明显征兆是: 程序中使用临时文件或流水线(pipeline)在不同进程间进行通信.

    188.使用图示来建模面向对象构架中类的关系.

    189.可以将源代码输入到建模工具中, 逆向推导出系统的构架.

    190.拥有大量同级子系统的系统, 常常按照分层构架进行组织.

    191.分层构架一般通过堆叠拥有标准化接口的软件组件来实现.

    192.系统中每个层可以将下面的层看作抽象实体, 并且(只要该层满足它的需求说明)不关心上面的层如何使用它.

    193.层的接口既可以是支持特定概念的互补函数族, 也可以是一系列支持同一抽象接口不同底层实现的可互换函数.

    194.用C语言实现的系统, 常常用函数指针的数组, 表达层接口的多路复用操作.

    195.用面向对象的语言实现的系统, 使用虚方法调用直接表达对层接口的多嘴复用操作.

    196.系统可以使用不同的|独特的层次分解模型跨各种坐标轴进行组织.

    197.使用程序切片技术, 可以将程序中的数据和控制之间依赖关系集中到一起.

    198.在并发系统中, 一个单独的系统组件起到集中式管理器的作用, 负责启动|停止和协调其他系统进程和任务的执行.

    199.许多现实的系统都会博采众家之长. 当处理此类系统时, 不要徒劳地寻找无所不包的构架图; 应该将不同构架风格作为独立但相关的实体

    来进行定位|识别并了解.

    200.状态变迁图常常有助于理清状态机的动作.

    201.在处理大量的代码时, 了解将代码分解成单独单元的机制极为重要.

    202.大多数情况下, 模块的物理边界是单个文件|组织到一个目录中的多个文件或拥有统一前缀的文件的集合.

    203.C中的模块, 由提供模块公开接口的头文件和提供对应实现的源文件组成.

    204.对象的构造函数经常用来分配与对象相关的资源, 并初始化对象的状态. 函数一般用来释放对象在生命期中占用的资源.

    205.对象方法经常使用类字段来存储控制所有方法运作的数据(比如查找表或字典)或维护类运作的状态信息(例如, 赋给每个对象一个标识符的

    计数器).

    206.在设计良好的类中, 所有的字段都应在声明为private, 并用公开的访问方法提供对它们的访问.

    207.在遇到friend声明时, 要停下来分析一下, 看看绕过类封装在设计上的理由.

    208.可以有节制地用运算符增强特定类的可用性, 但用运算符重载, 将类实现为拥有内建算术类型相关的全部功能的类实体, 是不恰当的.

    209.泛型实现不是在编译期间通过宏替换或语言所支持的功能(比如C++模板和Ada的泛型包)来实现, 就是在运行期间通过使用数据元素的指针

    和函数的指针|或对象的多态性实现.

    210.抽象数据类型经常用来封装常用的数据组织方案(比如树|列表或栈), 或者对用户隐藏数据类型的实现细节.

    211.使用库的目的多种多样: 重用源代码或目标代码, 组织模块集合, 组织和优化编译过程, 或是用来实现应用程序各种特性的按需载入.

    212.大型的|分布式的系统经常实现为许多互相协作的进程.

    213.对于基于文本的数据储存库, 可以通过浏览存储在其中的数据, 破译出它的结构.

    214.可以通过查询数据字典中的表, 或使用数据库专有的SQL命令, 比如show table, 来分析关系型数据库的模式.

    215.识别出重用的构架元素后, 可以查找其最初的描述, 了解正确地使用这种构架的方式, 以及可能出现的误用.

    216.要详细分析建立在某种框架之上的应用程序, 行动的最佳路线就是从研究框架自身开始.

    217.在阅读向导生成的代码时, 不要期望太高, 否则您会感到失望.

    218.学习几个基本的设计模式之后, 您会发现, 您查看代码构架的方式会发生改变: 您的视野和词汇将会扩展到能够识别和描述许多通用的形

    式.

    219.频繁使用的一些模式, 但并不显式地指出它们的名称, 这是由于构架性设计的重用经常先于模式的形成.

    220.请试着按照底层模式来理解构架, 即使代码中并没有明确地提及模式.

    221.大多数解释器都遵循类似的处理构架, 围绕一个状态机进行构建, 状态机的操作依赖于解释器的当前状态|程序指令和程序状态.

    222.多数情况下, 参考构架只是为应用程序域指定一种概念性的结构, 具体的实现并非必须遵照这种结构.

    第十章: 代码阅读工具
    223.词汇工具可以高效地在一个大代码文件中或者跨多个文件查找某种模式.

    224.使用程序编辑器和正则表达式查找命令, 浏览庞大的源代码文件.

    225.以只读方式浏览源代码文件.

    226.使用正则表达式 ^function name 可以找出函数的定义.

    227.使用正则表达式的字符类, 可以查找名称遵循特定模式的变量.

    228.使用正则表达式的否定字符类, 可以避免非积极匹配.

    229.使用正则表达式 symbol-1. *symbol-2, 可以查找出现在同一行的符号.

    230.使用编辑器的 tags 功能, 可以快速地找出实体的定义.

    231.可以用特定的 tag 创建工具, 增加编辑器的浏览功能.

    232.使用编辑器的大纲视图, 可以获得源代码结构的鸟瞰图.

    233.使用您的编辑器来检测源代码中圆括号|方括号和花括号的匹配.

    234.使用 grep 跨多个文件查找代码模式.

    235.使用 grep 定位符号的声明|定义和应用.

    236.当您不能精确地表述要查找的内容时, 请使用关键单词的词干对程序的源代码进行查找.

    237.用 grep 过滤其他工具生成的输出, 分离出您要查找的项.

    238.将 grep 的输出输送到其他工具, 使复杂处理任务自动化.

    239.通过对 grep 的输出进行流编辑, 重用代码查找的结果.

    240.通过选取与噪音模式不匹配的输出行(grep-v), 过滤虚假的 grep 输出.

    241.使用 fgrep 在源代码中查找字符串列表.

    242.查找注释, 或标识符大小写不敏感的语言编写的代码时, 要使用大小写不敏感的模式匹配(grep -i).

    243.使用 grep –n 命令行开关, 可以创建与给定正则表达式匹配的文件和行号的检查表.

    244.可以使用 diff 比较文件或程序不同版本之间的差别.

    245.在运行 diff 命令时, 可以使用 diff –b, 使文件比较算法忽略结尾的空格, 用 –w 忽略所有空白区域的差异, 用 –i 使文件比较对大小写不敏感.

    246.不要对创建自己的代码阅读工具心存畏惧.

    247.在构建自己的代码阅读工具时: 要充分利用现代快速原型语言所提供的能力; 从简单开始, 根据需要逐渐改进; 使用利用代码词汇结构的各种试探法; 要允许一些输出噪音或寂静(无关输出或缺失输出); 使用其他工具对输入进行预处理, 或者对输出进行后期处理.

    248.要使编译器成为您的: 指定恰当级别的编译器警告, 并小心地评估生成的结果.

    249.使用C预处理器理清那些滥用预处理器特性的程序.

    250.要彻底地了解编译器如何处理特定的代码块, 需要查看生成的符号(汇编)代码.

    251.通过分析相应目标文件中的符号, 可以清晰地了解源文件的输入和输出.

    252.使用源代码浏览器浏览大型的代码集合以及对象类型.

    253.要抵制住按照您的编码规范对外部代码进行美化的诱惑; 不必要的编排更改会创建不同的代码, 并妨碍工作的组织.

    254.优美打印程序和编辑器语法着色可以使得程序的源代码为易读.

    255.cdecl 程序可以将难以理解的C和C++类型声明转换成纯英语(反之亦然).

    256.实际运行程序, 往往可以更深刻地理解程序的动作.

    257.系统调用|事件和数据包跟踪程序可以增进对程序动作的理解.

    258.执行剖析器可以找出需要着重优化的代码, 验证输入数据的覆盖性, 以及分析算法的动作.

    259.通过检查从未执行的代码行, 可以找出测试覆盖的弱点, 并据此修正测试数据.

    260.要探究程序动态动作时的每个细节, 需要在调试器中运作它.

    261.将您觉得难以理解的代码打印到纸上.

    262.可以绘制图示来描绘代码的动作.

    263.可以试着向别人介绍您在阅读的代码, 这样做一般会增进您对代码的理解.

    264.理解复杂的算法或巧妙的数据结构, 要选择一个安静的环境, 然后聚精会神地考虑, 不要借助于任何计算机化或自动化的帮助.

    第十一章: 一个完整的例子
    265.模仿软件的功能时, 要依照相似实体的线路(类|函数|模块). 在相似的现有实体中, 为简化对源代码库的文本查找, 应选取比较罕见的名称.

    266.自动生成的文件常常会在文件的开关有一段注释, 说明这种情况.

    267.如果试图精确地分析代码, 一般会陷入数量众多的类|文件和模块中, 这些内容会很快将我们淹没; 因此, 我们必须将需要理解的代码限定在绝对必需的范围之内.

    268.采用一种广度优先查找策略, 从多方攻克代码阅读中存在的问题, 进到找出克服它们的方法为止
  • 如何阅读源代码(转)搜集整理的

    2007-03-23 17:46:33

    阅读源代码对于程序员来说是提高技术实力和业务知识最好的方法,那么我们怎样阅读源代码就是我们 首先要解决的问题。

          阅读源代码就像管理一家大的公司,关键在于管理者卓越的领导意识。作为阅读源代码的人也应该有良好的意识,在阅读源代码时才能事半功倍。养成良好的阅读习惯。

      阅读方法如下:

       1.对于一个大的项目,首先要弄清项目的框架结构和各个项目模块的功能(输入什么,处理以后输出什么). 在这一点上Ant工具做的相当到位,通过编写build.xmlxml的良好的语法结构可以清楚的看到框架。Make工具也做比较出色。具体细节可参考GNU Make /Apache Ant Manual.和程序的build.xmlmakefile文件。

           2. 参照源代码和对应文档及业务知识 掌握各个项目模块的主流程也就是先从每个模块的main函  数开始,按照顺序列出所用的函数,试着画流程图。注意:对于列出的函数我们现在只关心输入什么,处理后输出什么即函数的功能,不关心函数的实现UltraEdit32最新版阅读时十分方便。

            3.以上两步熟悉以后,在进一步熟悉各个项目模块的主流程,要弄清各个自定义函数的具体实现(标准库函数除外 原因:由厂商提供,厂商只提供函数的功能)。

          4.在每一步都要做好源代码阅读笔记,总结方法和技巧。每个项目的源代码阅读要多读几遍,书读百遍 其义之见 呵呵 定期与同仁切磋交流。

          5.提出更好的解决方案,(按照软件工程的设计步骤)评估方案的性能(界面,易用性,内存等方面).

          6.每日构建 具体参考构建工具和相关文挡。

     

  • C#.NET 中的类型转换(转贴)

    2007-03-23 17:20:48

    C# 出来也有些日子了,最近由于编程的需要,对 C# 的类型转换做了一些研究,其内容涉及 C# 的装箱/拆箱/别名、数值类型间相互转换、字符的 ASCII 码和 Unicode 码、数值字符串和数值之间的转换、字符串和字符数组/字节数组之间的转换、各种数值类型和字节数组之间的转换、十六进制数输出以及日期型数据的一些转换处理,在这里与大家分享——

    1. 装箱、拆箱还是别名

      许多 C#.NET 的书上都有介绍 int -> Int32 是一个装箱的过程,反之则是拆箱的过程。许多其它变量类型也是如此,如:short <-> Int16,long <-> Int64 等。对于一般的程序员来说,大可不必去了解这一过程,因为这些装箱和拆箱的动作都是可以自动完成的,不需要写代码进行干预。但是我们需要记住这些类型之间的关系,所以,我们使用“别名”来记忆它们之间的关系。
    C# 是全面向对象的语言,比 Java 的面向对象都还彻底——它把简单数据类型通过默认的装箱动作封装成了类。Int32、Int16、Int64 等就是相应的类名,而那些我们熟悉的、简单易记的名称,如 int、short、long 等,我们就可以把它称作是 Int32、Int16、Int64 等类型的别名。
      那么除了这三种类型之外,还有哪些类有“别名”呢?常用的有如下一些:

    bool -> System.Boolean (布尔型,其值为 true 或者 false)
    char -> System.Char (字符型,占有两个字节,表示 1 个 Unicode 字符)
    byte -> System.Byte (字节型,占 1 字节,表示 8 位正整数,范围 0 ~ 255)
    sbyte -> System.SByte (带符号字节型,占 1 字节,表示 8 位整数,范围 -128 ~ 127)
    ushort -> System.UInt16 (无符号短整型,占 2 字节,表示 16 位正整数,范围 0 ~ 65,535)
    uint -> System.UInt32 (无符号整型,占 4 字节,表示 32 位正整数,范围 0 ~ 4,294,967,295)
    ulong -> System.UInt64 (无符号长整型,占 8 字节,表示 64 位正整数,范围 0 ~ 大约 10 的 20 次方)
    short -> System.Int16 (短整型,占 2 字节,表示 16 位整数,范围 -32,768 ~ 32,767)
    int -> System.Int32 (整型,占 4 字节,表示 32 位整数,范围 -2,147,483,648 到 2,147,483,647)
    long -> System.Int64 (长整型,占 8 字节,表示 64 位整数,范围大约 -(10 的 19) 次方 到 10 的 19 次方)
    float -> System.Single (单精度浮点型,占 4 个字节)
    double -> System.Double (双精度浮点型,占 8 个字节)

      我们可以用下列代码做一个实验:

    private void TestAlias() {
        // this.textBox1 是一个文本框,类型为 System.Windows.Forms.TextBox
        // 设计中已经将其 Multiline 属性设置为 true
        byte a = 1; char b = 'a'; short c = 1;
        int d = 2; long e = 3; uint f = 4; bool g = true;
        this.textBox1.Text = "";
        this.textBox1.AppendText("byte -> " + a.GetType().FullName + "\n");
        this.textBox1.AppendText("char -> " + b.GetType().FullName + "\n");
        this.textBox1.AppendText("short -> " + c.GetType().FullName + "\n");
        this.textBox1.AppendText("int -> " + d.GetType().FullName + "\n");
        this.textBox1.AppendText("long -> " + e.GetType().FullName + "\n");
        this.textBox1.AppendText("uint -> " + f.GetType().FullName + "\n");
        this.textBox1.AppendText("bool -> " + g.GetType().FullName + "\n");
    }

      在窗体中新建一个按钮,并在它的单击事件中调用该 TestAlias() 函数,我们将看到运行结果如下:

    byte -> System.Byte
    char -> System.Char
    short -> System.Int16
    int -> System.Int32
    long -> System.Int64
    uint -> System.UInt32
    bool -> System.Boolean

      这足以说明各别名对应的类!

    2. 数值类型之间的相互转换

      这里所说的数值类型包括 byte, short, int, long, fload, double 等,根据这个排列顺序,各种类型的值依次可以向后自动进行转换。举个例来说,把一个 short 型的数据赋值给一个 int 型的变量,short 值会自动行转换成 int 型值,再赋给 int 型变量。如下例:

    private void TestBasic() {
        byte a = 1; short b = a; int c = b;
        long d = c; float e = d; double f = e;
        this.textBox1.Text = "";
        this.textBox1.AppendText("byte a = " + a.ToString() + "\n");
        this.textBox1.AppendText("short b = " + b.ToString() + "\n");
        this.textBox1.AppendText("int c = " + c.ToString() + "\n");
        this.textBox1.AppendText("long d = " + d.ToString() + "\n");
        this.textBox1.AppendText("float e = " + e.ToString() + "\n");
        this.textBox1.AppendText("double f = " + f.ToString() + "\n");
    }

      译顺利通过,运行结果是各变量的值均为 1;当然,它们的类型分别还是 System.Byte 型……System.Double 型。现在我们来试试,如果把赋值的顺序反过来会怎么样呢?在 TestBasic() 函数中追加如下语句:

    int g = 1;
    short h = g;
    this.textBox1.AppendText("h = " + h.ToString() + "\n");

      结果编译报错:
      G:\Projects\Visual C#\Convert\Form1.cs(118): 无法将类型“int”隐式转换为“short”
      其中,Form1.cs 的 118 行即 short h = g 所在行。

      这个时候,如果我们坚持要进行转换,就应该使用强制类型转换,这在 C 语言中常有提及,就是使用“(类型名) 变量名”形式的语句来对数据进行强制转换。如上例修改如下:

    short g = 1;
    byte h = (byte) g; // 将 short 型的 g 的值强制转换成 short 型后再赋给变量 h
    this.textBox1.AppendText("h = " + h.ToString() + "\n");

      编译通过,运行结果输出了 h = 1,转换成功。
      但是,如果我们使用强制转换,就不得不再考虑一个问题:short 型的范围是 -32768 ~ 23767,而 byte 型的范围是 0 ~ 255,那么,如果变量 g 的大小超过了 byte 型的范围又会出现什么样的情况呢?我们不妨再一次改写代码,将值改为 265,比 255 大 10

    short g = 265; //265 = 255 + 10
    byte h = (byte) g;
    this.textBox1.AppendText("h = " + h.ToString() + "\n");

      编译没有出错,运行结果却不是 h = 265,而是 h = 9。
    因此,我们在进行转换的时候,应当注意被转换的数据不能超出目标类型的范围。这不仅体现在多字节数据类型(相对,如上例的 short) 转换为少字节类型(相对,如上例的 byte) 时,也体现在字节数相同的有符号类型和无符号类型之间,如将 byte 的 129 转换为 sbyte 就会溢出。这方面的例子大同小异,就不详细说明了。

    3. 字符的 ASCII 码和 Unicode 码

      很多时候我们需要得到一个英文字符的 ASCII 码,或者一个汉字字符的 Unicode 码,或者从相关的编码查询它是哪一个字符的编码。很多人,尤其是从 VB 程序序转过来学 C# 的人,会报怨 C# 里为什么没有提供现成的函数来做这个事情——因为在 VB 中有 Asc() 函数和 Chr() 函数用于这类转换。
    但是如果你学过 C,你就会清楚,我们只需要将英文字符型数据强制转换成合适的数值型数据,就可以得到相应的 ASCII 码;反之,如果将一个合适的数值型数据强制转换成字符型数据,就可以得到相应的字符。
    C# 中字符的范围扩大了,不仅包含了单字节字符,也可以包含双字节字符,如中文字符等。而在字符和编码之间的转换,则仍延用了 C 语言的做法——强制转换。不妨看看下面的例子

    private void TestChar() {
        char ch = 'a'; short ii = 65;
        this.textBox1.Text = "";
        this.textBox1.AppendText("The ASCII code of \'" + ch + "\' is: " + (short) ch + "\n");
        this.textBox1.AppendText("ASCII is " + ii.ToString() + ", the char is: " + (char) ii + "\n");
        char cn = '中'; short uc = 22478;
        this.textBox1.AppendText("The Unicode of \'" + cn + "\' is: " + (short) cn + "\n");
        this.textBox1.AppendText("Unicode is " + uc.ToString() + ", the char is: " + (char) uc + "\n");
    }

      它的运行结果是

    The ASCII code of 'a' is: 97
    ASCII is 65, the char is: A
    The Unicode of '中' is: 20013
    Unicode is 22478, the char is: 城

      从这个例子中,我们便能非常清楚的了解——通过强制转换,可以得以字符的编码,或者得到编码表示的字符。如果你需要的不是 short 型的编码,请参考第 1 条进行转换,即可得到 int 等类型的编码值。

    4. 数值字符串和数值之间的转换

      首先,我们得搞明白,什么是数值字符串。我们知道,在 C# 中,字符串是用一对双引号包含的若干字符来表示的,如 "123"。而 "123" 又相对特殊,因为组成该字符串的字符都是数字,这样的字符串,就是数值字符串。在我们的眼中,这即是一串字符,也是一个数,但计算机却只认为它是一个字符串,不是数。因此,我们在某些时候,比如输入数值的时候,把字符串转换成数值;而在另一些时候,我们需要相反的转换。
      将数值转换成字符串非常简单,因为每一个类都有一个 void ToString() 方法。所有数值型的 void ToString() 方法都能将数据转换为数值字符串。如 123.ToSting() 就将得到字符串 "123"。
    那么反过来,将数值型字符串转换成数值又该怎么办呢?我们仔细查找一下,会发现 short, int, float 等数值类型均有一个 static Parse() 函数。这个函数就是用来将字符串转换为相应数值的。我们以一个 float 类型的转换为例: float f = float.Parse("543.21"); 其结果 f 的值为 543.21F。当然,其它的数值类型也可以使用同样的方法进行转换,下面的例子可以更明确的说明转换的方法:

    private void TestStringValue() {
        float f = 54.321F;
        string str = "123";
        this.textBox1.Text = "";
        this.textBox1.AppendText("f = " + f.ToString() + "\n");
        if (int.Parse(str) == 123) {
            this.textBox1.AppendText("str convert to int successfully.");
        } else {
            this.textBox1.AppendText("str convert to int failed.");
        }
    }

      运行结果:

    f = 54.321
    str convert to int successfully.

    5. 字符串和字符数组之间的转换

      字符串类 System.String 提供了一个 void ToCharArray() 方法,该方法可以实现字符串到字符数组的转换。如下例:

    private void TestStringChars() {
        string str = "mytest";
        char[] chars = str.ToCharArray();
        this.textBox1.Text = "";
        this.textBox1.AppendText("Length of \"mytest\" is " + str.Length + "\n");
        this.textBox1.AppendText("Length of char array is " + chars.Length + "\n");
        this.textBox1.AppendText("char[2] = " + chars[2] + "\n");
    }

      例中以对转换转换到的字符数组长度和它的一个元素进行了测试,结果如下:

    Length of "mytest" is 6
    Length of char array is 6
    char[2] = t

      可以看出,结果完全正确,这说明转换成功。那么反过来,要把字符数组转换成字符串又该如何呢?
      我们可以使用 System.String 类的构造函数来解决这个问题。System.String 类有两个构造函数是通过字符数组来构造的,即 String(char[]) 和 String[char[], int, int)。后者之所以多两个参数,是因为可以指定用字符数组中的哪一部分来构造字符串。而前者则是用字符数组的全部元素来构造字符串。我们以前者为例,在 TestStringChars() 函数中输入如下语句:

    char[] tcs = {'t', 'e', 's', 't', ' ', 'm', 'e'};
    string tstr = new String(tcs);
    this.textBox1.AppendText("tstr = \"" + tstr + "\"\n");

      运行结果输入 tstr = "test me",测试说明转换成功。
      实际上,我们在很多时候需要把字符串转换成字符数组只是为了得到该字符串中的某个字符。如果只是为了这个目的,那大可不必兴师动众的去进行转换,我们只需要使用 System.String 的 [] 运算符就可以达到目的。请看下例,再在 TestStringChars() 函数中加入如如下语名:

    char ch = tstr[3];
    this.textBox1.AppendText("\"" + tstr + "\"[3] = " + ch.ToString());

      正确的输出是 "test me"[3] = t,经测试,输出正确。

    6. 字符串和字节数组之间的转换

      如果还想从 System.String 类中找到方法进行字符串和字节数组之间的转换,恐怕你会失望了。为了进行这样的转换,我们不得不借助另一个类:System.Text.Encoding。该类提供了 bye[] GetBytes(string) 方法将字符串转换成字节数组,还提供了 string GetString(byte[]) 方法将字节数组转换成字符串。
      System.Text.Encoding 类似乎没有可用的构造函数,但我们可以找到几个默认的 Encoding,即 Encoding.Default(获取系统的当前 ANSI 代码页的编码)、Encoding.ASCII(获取 7 位 ASCII 字符集的编码)、Encoding.Unicode(获取采用 Little-Endian 字节顺序的 Unicode 格式的编码)、Encoding.UTF7(获取 UTF-7 格式的编码)、Encoding.UTF8(获取 UTF-8 格式的编码) 等。这里主要说说 Encoding.Default 和 Encoding.Unicode 用于转换的区别。
      在字符串转换到字节数组的过程中,Encoding.Default 会将每个单字节字符,如半角英文,转换成 1 个字节,而把每个双字节字符,如汉字,转换成 2 个字节。而 Encoding.Unicode 则会将它们都转换成两个字节。我们可以通过下列简单的了解一下转换的方法,以及使用 Encoding.Default 和 Encodeing.Unicode 的区别:

    private void TestStringBytes() {
        string s = "C#语言";
        byte[] b1 = System.Text.Encoding.Default.GetBytes(s);
        byte[] b2 = System.Text.Encoding.Unicode.GetBytes(s);
        string t1 = "", t2 = "";
        foreach (byte b in b1) {
            t1 += b.ToString("") + " ";
        }
        foreach (byte b in b2) {
            t2 += b.ToString("") + " ";
        }
        this.textBox1.Text = "";
        this.textBox1.AppendText("b1.Length = " + b1.Length + "\n");
        this.textBox1.AppendText(t1 + "\n");
        this.textBox1.AppendText("b2.Length = " + b2.Length + "\n");
        this.textBox1.AppendText(t2 + "\n");
    }
    

      运行结果如下,不说详述,相信大家已经明白了。

    b1.Length = 6
    67 35 211 239 209 212
    b2.Length = 8
    67 0 35 0 237 139 0 138

      将字节数组转换成字符串,使用 Encoding 类的 string GetString(byte[]) 或 string GetString(byte[], int, int) 方法,具体使用何种 Encoding 还是由编码决定。在 TestStringBytes() 函数中添加如下语句作为实例:

    byte[] bs = {97, 98, 99, 100, 101, 102};
    string ss = System.Text.Encoding.ASCII.GetString(bs);
    this.textBox1.AppendText("The string is: " + ss + "\n");

      运行结果为:The string is: abcdef

    7. 各种数值类型和字节数组之间的转换

      在第 1 条中我们可以查到各种数值型需要使用多少字节的空间来保存数据。将某种数值类型的数据转换成字节数组的时候,得到的一定是相应大小的字节数组;同样,需要把字节数组转换成数值类型,也需要这个字节数组大于相应数值类型的字节数。
      现在介绍此类转换的主角:System.BitConverter。该类提供了 byte[] GetBytes(...) 方法将各种数值类型转换成字节数组,也提供了 ToInt32、ToInt16、ToInt64、ToUInt32、ToSignle、ToBoolean 等方法将字节数组转换成相应的数值类型。

      由于这类转换通常只是在需要进行较细微的编码/解码操作时才会用到,所以这里就不详细叙述了,仅把 System.BitConverter 类介绍给大家。

    8. 转换成十六进制

      任何数据在计算机内部都是以二进制保存的,所以进制与数据的存储无关,只与输入输出有关。所以,对于进制转换,我们只关心字符串中的结果。
      在上面的第 4 条中提到了 ToString() 方法可以将数值转换成字符串,不过在字符串中,结果是以十进制显示的。现在我们带给它加一些参数,就可以将其转换成十六进制——使用 ToString(string) 方法。
      这里需要一个 string 类型的参数,这就是格式说明符。十六进制的格式说明符是 "x" 或者 "X",使用这两种格式说明符的区别主要在于 A-F 六个数字:"x" 代表 a-f 使用小写字母表示,而 "X" 而表示 A-F 使用大字字母表示。如下例:

    private void TestHex() {
        int a = 188;
        this.textBox1.Text = "";
        this.textBox1.AppendText("a(10) = " + a.ToString() + "\n");
        this.textBox1.AppendText("a(16) = " + a.ToString("x") + "\n");
        this.textBox1.AppendText("a(16) = " + a.ToString("X") + "\n");
    }

      运行结果如下:

    a(10) = 188
    a(16) = bc
    a(16) = BC

      这时候,我们可能有另一种需求,即为了显示结果的整齐,我们需要控制十六进制表示的长度,如果长度不够,用前导的 0 填补。解决这个问题,我们只需要在格式说明符“x”或者“X”后写上表示长度的数字就行了。比如,要限制在 4 个字符的长度,可以写成“X4”。在上例中追加一句:

    this.textBox1.AppendText("a(16) = " + a.ToString("X4") + "\n");

      其结果将输出 a(16) = 00BC。
      现在,我们还要说一说如何将一个表示十六进制数的字符串转换成整型。这一转换,同样需要借助于 Parse() 方法。这里,我需要 Parse(string, System.Globalization.NumberStyles) 方法。第一个参数是表示十六进制数的字符串,如“AB”、“20”(表示十进制的 32) 等。第二个参数 System.Globalization.NumberStyles 是一个枚举类型,用来表示十六进制的枚举值是 HexNumber。因此,如果我们要将“AB”转换成整型,就应该这样写:int b = int.Parse("AB", System.Globalization.NumberStyles.HexNumber),最后得到的 b 的值是 171。

    9. 日期型数据和长整型数据之间的转换

      为什么要将日期型数据转换为长整型数据呢?原因很多,但就我个人来说,经常将它用于数据库的日期存储。由于各种数据库对日期型的定义和处理是不一样的,各种语言对日期型数据的定义的处理也各不相同,因为,我宁愿将日期型数据转换成长整型再保存到数据库中。虽然也可以使用字符串来保存,但使用字符串也会涉及到许多问题,如区域等问题,而且,它需要比保存长整型数据更多的空间。
      日期型数据,在 C# 中的参与运算的时候,应该也是转换为长整型数据来运算的。它的长整型值是自 0001 年 1 月 1 日午夜 12:00 以来所经过时间以 100 毫微秒为间隔表示时的数字。这个数在 C# 的 DateTime 中被称为 Ticks(刻度)。DateTime 类型有一个名为 Ticks 的长整型只读属性,就保存着这个值。如此,要从一个 DataTime 型数据得到 long 型值就非常简单了,只需要读出 DataTime 对象的 Ticks 值即可,如:

    long longDate = DateTime.Now.Ticks;

      DateTime 的构造函数中也提供了相应的,从长整型数据构造 DateTime 型数据的函数:DateTime(long)。如:

    DateTime theDate = new DateTime(longDate);

      但这样对于很多 VB6 程序员来说,是给他们出了一道难题,因为 VB6 中的日期型数据内部是以 Double 型表示的,将其转换为长整型后得到的仅仅是日期,而没有时间。如何协调这两种日期类型呢?
    System.DateTime 提供了 double ToOADate() 和 static DateTime FromOADate(double) 两个函数来解决这个问题。前者将当前对象按原来的 double 值输出,后者则从一个 double 值获得一个 System.DateTime 对象。举例如下:

    private void TestDateTimeLong() {
        double doubleDate = DateTime.Now.ToOADate();
        DateTime theDate = DateTime.FromOADate(doubleDate);
        this.textBox1.Text = "";
        this.textBox1.AppendText("Double value of now: " + doubleDate.ToString() + "\n");
        this.textBox1.AppendText("DateTime from double value: " + theDate.ToString() + "\n");
    }

      运行结果:

    Double value of now: 37494.661541713
    DateTime from double value: 2002-8-26 15:52:37

    10. 格式化日期型数据

      编程的过程中,通常需要将日期型数据按照一定的格式输出,当然,输出结果肯定是字符串。为此,我们需要使用 System.DateTime 类的 ToString() 方法,并为其指定格式字符串。
      MSDN 中,System.Globalization.DateTimeFormatInfo 类的概述里对模式字符串有非常详细的说明,因此,这里我只对常用的一些格式进行说明,首先请看下表:

    d 月中的某一天 一位数的日期没有前导零
    dd 月中的某一天 一位数的日期有一个前导零
    ddd 周中某天的缩写名称 在 AbbreviatedDayNames 中定义
    dddd 周中某天的完整名称 在 DayNames 中定义
    M 月份数字 一位数的月份没有前导零
    MM 月份数字 一位数的月份有一个前导零
    MMM 月份的缩写名称 在 AbbreviatedMonthNames 中定义
    MMMM 月份的完整名称 在 MonthNames 中定义
    y 不包含纪元的年份 如果不包含纪元的年份小于 10,则显示不具有前导零的年份
    yy 不包含纪元的年份 如果不包含纪元的年份小于 10,则显示具有前导零的年份
    yyyy 包括纪元的四位数的年份  
    h 12 小时制的小时 一位数的小时数没有前导零
    hh 12 小时制的小时 一位数的小时数有前导零
    H 24 小时制的小时 一位数的小时数没有前导零
    HH 24 小时制的小时 一位数的小时数有前导零
    m 分钟 一位数的分钟数没有前导零
    mm 分钟 一位数的分钟数有一个前导零
    s 一位数的秒数没有前导零
    ss 一位数的秒数有一个前导零

      为了便于大家的理解,不妨试试下面的程序:

    private void TestDateTimeToString() {
        DateTime now = DateTime.Now;
        string format;
        this.textBox1.Text = "";
        format = "yyyy-MM-dd HH:mm:ss";
        this.textBox1.AppendText(format + ": " + now.ToString(format) + "\n");
        format = "yy年M日d日";
        this.textBox1.AppendText(format + ": " + now.ToString(format) + "\n");
    }

      这段程序将输出结果:

    yyyy-MM-dd HH:mm:ss: 2002-08-26 17:03:04
    yy年M日d日: 02年8日26日

      这时候,又出现一个问题,如果要输出的文本信息中包含格式字符怎么办?如

    format = "year: yyyy, month: MM, day: dd";
    this.textBox1.AppendText(now.ToString(format) + "\n");

      将输出:

    2ear: 2002, 4on下5: 08, 26a2: 26

      这并不是我想要的结果,怎么办呢?有办法——

    format = "\"year\": yyyy, \'month\': MM, \'day\': dd";
    this.textBox1.AppendText(now.ToString(format) + "\n");

      看,这次运行结果对了:

    year: 2002, month: 08, day: 26

      可以看出,只需要使用单引号或者双引号将文本信息括起来就好。
      如果文本信息中包含双引号或者单引号又怎么办呢?这个问题,请读者们动动脑筋吧!


  • Description 对象用于编程描述

    2007-03-21 15:21:02

    将 Descrīption 对象用于编程描述
    使用 Descrīption 对象可以返回包含一组 Property 对象的 Properties 集合对象。Property 对象由属性名和值组成。然后,可以在语句中指定用返回的 Properties 集合代替对象名。(每个 property 对象都包含一个属性名和值对。)

    注意:默认情况下,添加到 Properties 集合的所有 Property 对象的值都将作为正则表达式处理。因此,如果希望输入包含特殊正则表达式字符(例如 *、? 和 +)的值,请使用 \(反斜杠)字符指示 QuickTest 将特殊字符作为文字字符处理。有关正则表达式的详细信息,请参阅了解和使用正则表达式。

    可以将 RegularExpression 属性设置为 False,以便将集合中特定 Property 对象的值指定为文字值。有关详细信息,请参阅《QuickTest Professional Object Model Reference》(英语版)的“实用程序”部分。

    要创建 Properties 集合,可以使用以下语法输入 Descrīption.Create 语句:

    Set MyDescrīption = Descrīption.Create()

    创建 Properties 对象(例如,以上示例中的 MyDescrīption)后,就可以输入语句,以便在运行会话期间在 Properties 对象中添加、编辑、删除或检索属性和值。这样,您可以在运行会话期间,使用动态方法确定哪个属性以及多少个属性应包含在对象描述中。

    在 Properties 集合中填充一组 Property 对象(属性和值)后,可以在测试语句中指定用 Properties 对象代替对象名。

    例如,您无须输入:

    Window("Error").WinButton("text:=OK", "width:=50").Click

    而可以输入:

    Set MyDescrīption = Descrīption.Create()
    MyDescrīption("text").Value = "OK"
    MyDescrīption("width").Value = 50
    Window("Error").WinButton(MyDescrīption).Click

    注意:在测试对象层次中的特定位置使用编程描述后,在相同语句中该位置的后面部分,必须继续使用编程描述。如果在层次中使用编程描述说明的其他对象的后面,您按对象库名指定了某个测试对象,则 QuickTest 将无法识别该对象。

    例如,您可以使用 Browser(Desc1).Page(Desc1).Link(desc3),因为该语句在整个测试对象层次中使用编程描述。

    您也可以使用 Browser("Index").Page(Desc1).Link(desc3),因为该语句从描述中的特定位置(从 Page 对象描述开始)开始使用编程描述。

    不过,您不能使用 Browser(Desc1).Page(Desc1).Link("Example1"),因为该语句对 Browser 和 Page 对象使用编程描述,但又试图对 Link 测试对象使用对象库名(QuickTest 尝试根据名称来查找 Link 对象,但无法在库中找到该对象,因为父对象是使用编程描述指定的)。

    使用 Properties 对象时,可以将变量名用于属性或值,以便根据运行会话期间检索的属性和值来生成对象描述。

    如果希望对多个对象使用编程描述,则可以在测试或组件中创建多个 Properties 对象。

     

  • 描述性编程(转载2)

    2007-03-21 15:19:40

    录制的脚本:

    Dialog("Login").WinEdit("Agent Name:").Type "YYYYYY"
    Dialog("Login").WinEdit("Agent Name:").Set "yyyyy"
    Dialog("Login").WinEdit("Password:").SetSecure "45e7bace1f2e4161d1f6108a1151235a46dde145"
    Dialog("Login").WinEdit("Password:").Type  micReturn
    Dialog("Flight Reservations").WinButton("确定").Click
    用描述性编程编写的脚本
    Dialog("text:=Login").WinEdit("attached text:=Agent Name:").Set "YYYY"
    Dialog("text:=Login").WinEdit("attached text:=Password:").SetSecure "45e7b79479d8c49df2749048f22ae14fd5437c8b"
    Dialog("text:=Login").WinButton("text:=OK").Click
    Dialog("text:=Flight Reservations").WinButton("text:=确定").Click

    当然值得注意的是,如果父对象用描述性编程表示了,那么后面的对象都要用描述性编程表示了.如:

    Dialog("text:=Login").WinEdit("attached text:=Agent Name:").Set "mercury"

    这边Dialog("text:=Login")用描述性编程表示了,那么WinEdit("attached text:=Agent Name:")
    就必须要描述性编程表示了.因为在对象库中,子对象是依靠父对象存在的.所以如果Dialog("text:=Login")
    这个父对象从对象库中删除了,那么后面的子对象也同时被删除了.反过来子对象删除就不影响父对象.所以
    子对象可以单独用描述性编程表示,而不需牵连其他对象.

     

  • 如何调用vbs

    2007-03-21 15:18:18

    假设c盘下有MyFuction.vbs这个脚本
    Function MessgeBox()
    msgbox "test!"
    End Function

    方法一
    ExecuteFile  "c:\MyFuction.vbs"
    MessgeBox()
    方法2
    选择菜单 test---〉settings---〉resourse
    点击加号,选择vb脚本的路径点击 ok
    在expert view 中输入
    MessageBox()

  • qtp 基础代码---转载

    2007-03-21 15:12:52

    qtp 基础代码---转载自51testing中的kai_top 网友。

    1 生产随机数列
    第一种方法

    CODE:

    [Copy to clipboard]

    randomize'更新反回的数据
    funcation rand(k,n)
    n=int((k-1)*rnd+1)
    rand=n
    end funcation

    第二种方法

    CODE:

    [Copy to clipboard]

    n=randomnumber.value(1,255)

    2  当运行到表中的某一行,自动导出表中的所有数据

    CODE:

    [Copy to clipboard]

    row=datatable.getcurrentrow
    if row="5" then
      datatable.export("d:\data.xml")
    end if

    3

    CODE:

    [Copy to clipboard]

    webedit("txtpass").setsecure"sdsdf...."

    如果参数化密码,可以直接在数据表中写入未加密的密码,它会自动识别,即不用把setsecure改为set
    4
     如果弹出对话框就获取上面提示信息并与表中的信息对比,不统一证明弹出的提示出错,主要用来验证

    CODE:

    [Copy to clipboard]

     if browser("web_name").dialog("dialog_name").exist(1) then'如果不出现=false
         error_message=browser("web_name").dialog("diaglog_name").static("
    用户密码错误!".getRoproperty("text")
       if error_message<>(datatable.value("error_info"))then
             msgbox(error_message)
          end if
         browser("web_name").dialog("diaglog_name").close
      end if

    这里我总结了两点技巧:
      一是:对于dialog中,虽然提示信息对象名称是"用户密码错误",但如果信息对象名称是该用户不存在,不用更改会自动识别,我想主要是录制第一遍时,用户密码错误只是让运行时能找到这个控制,而不管它是什么内容,因为在对象仓库中,text不是决定该对象的属性
       
    二是:如果对于提示信息比较长的,可以用mid(error_message,n,m)取一部份特征提示信息进行验证,这样我想可以节省处理时间,又可以避免长度以及空格等字符的处理
    5  datatable.value("num")
    只在global形式下的一种省略形式;完整形式
    :

    CODE:

    [Copy to clipboard]

    datatable.value("num",dtlocalsheet)

    -----向某一列的单元格赋值:

    CODE:

    [Copy to clipboard]

    datatable.value("column_name",dtlocalsheet)="nanjing"

    -----取得某一行具体值:

    CODE:

    [Copy to clipboard]

    datatable.setcurrentrow(n)
    msgbox(datatable.getsheet("global").getparameter("column_name").Rawvalue)
    或者kk=datatable.Rawvalue("column_name","action1")

    ----run-time时,动态添加表格与数据

    CODE:

    [Copy to clipboard]

    kk=datatable.addsheet("sheet_name").addparameter("column_name","value").name;

    6  简化代码,明晰结构的方式with--end with 结构:

    CODE:

    [Copy to clipboard]

    with Dialog("name")
           c1=.button("b_name").click'//
    等价于Dialog("name").button("b_name").click
    end with

    7   wintreeview一些操作

    CODE:

    [Copy to clipboard]

    选择一个条目:wintreeview.select(item)'根是0
    根的名称:wintreeview.getitem(0)

    8   数据库检查点模块:

    CODE:

    [Copy to clipboard]

    sub database_check
    set con=createobject("adodb.connection")
    con.open "Descrīption=IBM_ODBC;DRIVER=SQL Server;SERVER=IBM;UID=sa;"&_
                     "PWD=123456;APP=Quick Test Pro;WSID=IBM;DATABASE=IBM_table"
    'access
    方式:con.open "DRIVER={Microsoft Access Driver (*.mdb)};DBQ=d:\test.mdb"
    'Orocle
    方式:con.open "DRIVER={Oracle in OraHome92};SERVER=CESHI;UID=CND_TEST;PWD=CND;DBQ=CESHI;DBA=W;APA=T;EXC=F;XSM=Default;FEN=T;QTO=T;FRC=10;FDL=10;LOB=T;RST=T;GDE=F;FRL=Lo;BAM=IfAllSuccessful;MTS=F;MDI=Me;CSR=F;FWC=F;PFC=10;TLO=O;"
    set record=createobject("adodb.recordset")
    sql="select*from ibm_one_table"
    record.open sql,con
    DO
    if(record("ibm_table_column")="kai")then'//
    查找表格中有多少kai
    num=num+1;
    end if
    record.movenext
    loop until record.eof=true
    record.close
    set record=nothing
    con.close
    set con=nothing
    end sub

    9   换行符

    CODE:

    [Copy to clipboard]

    vbcr----chr(13)回车符
        vblf----chr(10)
    换行符
        vbcrlf----chr(13)+chr(10)
    结合

    10  Run from step有两种方式:

    CODE:

    [Copy to clipboard]

    Keyword View模式会从本步骤运行到所有action结束
    expert view模式仅会将本action运行结束

    11  对于属性是变化的,有时可以把该属性从识别对象里删除,来解决识别问题
    12  
    对系统文件的操作

    CODE:

    [Copy to clipboard]

    -------从系统的文件中获取信息及删除文件
      get_file_infor("c:\she.mpg")
       function get_file_infor(url)
        dim fso,f
        set fso=createobject("scrīpting.filesystemobject")
        set f=fso.getfile(url)
        f.name:f.size:f.type:f.datacreated'///
    获取文件信息
        fso.deletefile(url)'/////
    删除文件
       end function
    --------
    获取文件夹里所有文件信息
    get_folder_infor("c:\kai")
    function get_folder_infor(folder)
    dim fso,f,f1,n
    set fso=createobject("scrīpting,filesystemobject")
    set f=fso.getfolder(folder)
    set fc=f.files
    for each f1 in fc
    select case f1.name
    case"kai.mpg","she.mpg","dd.mp3"'//
    检查文件夹里是否含有这些文件
    end select
    next
    end function

    13   等待某个对象出现方法

    CODE:

    [Copy to clipboard]

    y=......waitproperty("visible",true,10000)

    14   防程序中断方法

    CODE:

    [Copy to clipboard]

    On error resume next
    On error goto handle

    15  数组的应用:

    CODE:

    [Copy to clipboard]

    name=array(1,2,"aa","bb")
    name(2)="aa"

    16  正则表达式应用模板

    CODE:

    [Copy to clipboard]

    进行日期YYYY-MM-DD的格式检查 :
    Function RegExpTest(patrn, strng)
      Dim regEx, Match, Matches      ' Create variable.
      Set regEx = New RegExp         ' Create a regular expression.
      regEx.Pattern = patrn         ' Set pattern.
      regEx.IgnoreCase = True         ' Set case insensitivity.
      regEx.Global = True         ' Set global applicability.
      Set Matches = regEx.Execute(strng)   ' Execute search.
      For Each Match in Matches      ' Iterate Matches collection.
        RetStr = RetStr & "Match found at position "
        RetStr = RetStr & Match.FirstIndex & ". Match Value is '"
        RetStr = RetStr & Match.Value & "'." & vbCRLF
      Next
      RegExpTest = RetStr
    End Function
    date_pattern="^((((19|20)(([02468][048])|([13579][26]))-02-29))|((20[0-9][0-9])|(19[0-9][0-9]))-((((0[1-9])|(1[0-2]))-((0[1-9])|(1\d)|(2[0-8])))|((((0[13578])|(1[02]))-31)|(((01,3-9])|(1[0-2]))-(29|30)))))$"
    result_message=RegExpTest(date_pattern, inputbox("
    请你输入要检查的时间:"))'用其它正则表达式更改此处
    Select case result_message
    Case ""
             msgbox("
    你输入的日期格式与标准不匹配")
    case else  MsgBox(result_message)
    end select

    17   返回一个字符串在另一字符串中的位置

    CODE:

    [Copy to clipboard]

    instr(string1,string2)

    18   有时回放出现找不到对象时,可能不是由于你的代码问题,而是由于你的操作系统等设置问题;

    CODE:

    [Copy to clipboard]

    举例说明1
    比如:你录制一个选择磁盘中的文件动作
    会录制为:
    .winlistview("  ").drap 46,99
    .winlistview("  ").draponitem "she.mp3"
    下次录制的时候,如果你的系统文件改为不显示扩展名,下次执行的时候,QTP就找不到she.mp3,只能找到she;
    举例说明2
    有时由于不同操作系统以及不同的ie,导致有些窗口不能识别,比如在2000下弹出的网页对话框的标题是:
    “web
    对话框",而在2003上是网页对话框"

    19  "is+*"类型function

    CODE:

    [Copy to clipboard]

    isarray'是否是数组
    isconnected'
    判断QTP是否连接到TD
    isdate'
    是否是合法的日期类型
    isempty'
    判断是否初始化
    isNull'
    判断是否为空值
    isNumeric'
    判断是否是数字型
    isobject'
    判断是否一个功能对象
    isready'
    判断设备是否准备就绪
    isRootFolder'
    是否是根目录

     

  • 描述性编程(转载)

    2007-03-21 15:04:33

    文章出处:www.51testing.com / 作者:周坚

    描述性编程(descrīptive programming

    1
    descrīptive programming概述

    通常情况下,当在录制一个操作时,QTP会将被操作对象加入到对象库里(Object Repository)。一旦对象存在于对象库里,我们就可以在专家视图里通过添加相关的对象方法来对该对象进行操作。我们可以通过引用层次型对象库里的对象描述(Object Descrīption)来添加相应的方法。

    因为QTP对象库中的每个对象都具有唯一名称,所以在引用时对象名是必须需要指定的。然后在测试运行期间,QTP在对象库中根据这个对象的名称和父对象来查找对象,并使用为这个测试对象存储的测试对象描述,在网站或应用程序中标识该对象。

    例如我们用QTP录制Yahoo Mail登录情况时我们需要输入用户名,于是在录制时我们就会录下一个WebEdit对象,它的缺省逻辑名为“login”,该编辑字段位于名为“Yahoo! Mail - The best” 的页面上,并且该页面在浏览器中使用名称Yahoo!进行录制。

    那么如果我们想要应用该对象,就可以在专家视图输入以下信息:

    Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").Set “xxx”

    或者我们也可以调用一些方法,获取改对象在运行时的对象名,如:

    Browser("Yahoo!").Page("Yahoo! Mail - The best").WebEdit("login").GetROProperty(“name”)

    然而,我们可以发觉到,上面的例子在处理对象时,对象已经存在于对象库里,因此我们可以应用这个对象的逻辑名。实际使用中,情况往往并非如此简单,我们经常会遇到很多在页面上动态产生的对象,换而言之,对象库里没有这些对象,我们也无从引用。因此我们必须采用其他的技术来完成这类操作,这也就是我们需要讲解的Descrīptive Programming

    为了满足上面提到的动态对象的处理问题,QTP允许用户通过将对象属性编码到测试脚本里来动态识别对象,这就是我们通常意义下称为的Descrīptive Programming。通过这种方式,我们可以指示QTP不通过引用对象库和对象名来对实际对象进行操作。具体操作中,我们只需要为QTP提供对象的一组属性和值,这样QTP就可以来识别相应的对象并对其进行操作。这相当于,告诉QTP要识别对象的一些关键特征,根据这些特征QTP就可以一一匹配然后识别出来这个对象。

    而且,更为重要的是,通过这种Descrīptive Programming的方式,还可以让QTP识别具有某些相同属性的对象。我们先来举个例子来看一下:我们假设当前的Windows系统中打开了若干的Yahoo主页面(多于一个),现在我们要关闭所有的正在浏览Yahoo主页面的浏览器。

    对于上面那个例子来说,我们先看一个简单一点的情况,假设只有且仅有一个Yahoo主页面:那么我们可以用下面的方法来

    Window("Text:=Yahoo! - Microsoft Internet Explorer").Close

    我们可以看到语句里我们要查找的对象是Window窗口标题为“Yahoo! - Microsoft Internet Explorer”,然后把它关闭,具体的语法说明我们稍后为解释。但是上面的语句仅仅适合前面提到的条件只有且仅有一个Yahoo主页面,如果有多个同样的窗口就会出错,原因是通过语句可以匹配到多个对象,而QTP不知道应该对哪个对象进行关闭动作。我们需要进一步的缩小匹配范围:

    Dim i

    i = 0

    while (Window("Text:="Yahoo!" - Microsoft Internet Explorer", "index:="&i).exist)

    Window("Text:=Yahoo! - Microsoft Internet Explorer", "index:="&i).close

    i = i +1

    wend

    这里我们可以看到,对于具有相同属性的对象,我们可以通过index参数来对其进行区别,第一个对象为index=0,第二个为index=1等等,依次类推。当然我们还可以通过CreationTimeLocation参数来定位对象,这里就不详细叙述了。

    通过上面的例子,我们对Descrīptive Programming有一个基本了解了,下面我们详细讲解一下Descrīptive Programming:在具体实现中,我们有两种类型的Descrīptive Programming方法。可以列出直接在测试语句中描述对象的属性和值的集合;或者向Descrīption 对象中添加属性和值的集合,然后在语句中输入Descrīption 对象的名称。下面我们分别举例介绍。

    2
    、直接在语句中输入编程描述

    通过多个指定描述对象的property:=value对,可以直接在语句中描述对象,这是最直接有效的方法。

    常规语法为:

    TestObject("PropertyName1:=PropertyValue1", "..." , "PropertyNameX:="PropertyValueX""} 

    TestObject - 
    测试对象的类。

    PropertyName:=PropertyValue - 
    测试对象的属性及其值。各个property:="value" 对之间应用逗号和引号分开。

    例如:以下语句指定Mercury Tours 页面中名为author且索引值为WebEdit 测试对象。当测试运行时,QTP 将查找具有匹配属性值的WebEdit 对象,并输入文本jojo

    Browser("Mercury Tours").Page("Mercury Tours").WebEdit("Name:="Author"", "Index:="3"").Set "Mark Twain" 

    我们也可以从从描述中的特定位置(从Page 对象描述开始)开始使用Descrīptive Programming

    Browser("Mercury Tours").Page("Title:="Mercury" Tours").WebEdit("Name:="Author"", "Index:="3"").Set "jojo" 

    此外,如果我们希望在在一个测试或组件中多次使用相同的Descrīptive Programming,则可以将创建的对象赋值给变量,这样使用会方便很多。

    例如:我们需要完成下面一系列操作

    Window("Text:=HyperSna").WinButton("Caption:=
    日期").Click

    Window("Text:=HyperSna").WinButton("Caption:=
    时间").Click

    Window("Text:=HyperSna").WinButton("Caption:=
    确定").Click

    那么,为了方便其见,我们可以将Window("Text:=HyperSna")赋值到一个变量,然后再使用,参见下面的代码:

    Set WinHyper = Window("Text:="HyperSna"") 

    WinHyper.WinButton("Caption:=
    日期").Click

    WinHyper.WinButton("Caption:=
    时间").Click

    WinHyper.WinButton("Caption:=
    确定").Click

    如果使用了VBscrīpt里面的With语句,还可以简化为以下代码:

    With Window("Text:="HyperSna"") 

    .WinButton("Caption:=
    日期").Click 

    .WinButton("Caption:=
    时间").Click

    .WinButton("Caption:=
    确定").Click

    End With 

    下面我们来看一个更为详细的例子,在QTP产品缺省安装里面自带了一个网上订机票的示例称为Mercury Tour,我们看一下在订票过程中何时需要用Descrīptive Programming

    首先登入系统后,如果需要订票,就要先搜索航班,此时系统要求输入订票乘客的数量,假设我们在第一次录制脚本时选择了1Passenger,并成功完成订票。然后,我们需要参数化乘客数量来测试订票系统,我们会发现回放会失败。原因在于,不同的乘客的数量导致在订票时需要输入每个乘客的姓名,而录制时,只输入了一个乘客的姓名。而乘客姓名的输入框是随着乘客数量的变化而动态生成的,我们不可能从对象库里得到没有录制的对象,因此必须使用Descrīptive Programming


    在录制单个乘客时,我们得到的录制语句是:

    Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passFirst0").Set "Michael"

    Browser("Welcome: Mercury Tours").Page("Book a Flight: Mercury").WebEdit("passLast0").Set "Wang"

    显然WebEdit("passFirst0")WebEdit("passLast0")是录制时产生的对象并存放到对象库里的。通过对象库,我们可以看到对象的属性如下

    系统对于发生多个FirstName时,命名规则是passFirst0passFirst1…依次类推。因此只要通过简单的Descrīptive Programming就可以完成动态FirstNameLastName的识别工作。这里我们假设参数化的乘客数已经赋值给intPassNum,下面是脚本中的关键语句:

    counter = 0

    For i = 0 to (intPassNum)

    Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passFirst""&i).Set "Michael"

    Browser("Find a Flight:").Page("Book a Flight:").WebEdit("name:="passLast""&i).Set "Wang"

    counter = counter + 1

    Next

    3
    、使用descrīption对象

    使用Descrīption 对象可以返回包含一组Property 对象的Properties 集合对象。Property 对象由属性名和值组成。然后,可以在语句中指定用返回的Properties 集合代替对象名。(每个property 对象都包含一个属性名和值)。

    要创建Properties 集合,可以使用以下语法输入Descrīption.Create 语句:

    Set MyDescrīption = Descrīption.Create() 

    创建Properties 对象(例如,以上示例中的MyDescrīption)后,就可以输入语句,以便在运行会话期间在Properties 对象中添加、编辑、删除或检索属性和值。这样,就可以在运行会话期间,使用动态方法确定哪个属性以及多少个属性应包含在对象描述中。

    Properties  查看(828) 评论(0) 收藏 分享 管理

  • 边界值测试2(转载)

    2007-03-20 14:14:51

    边界值分析也是一种黑盒测试方法,适度等价类分析方法的一种补充,由长期的测试工作经验得知,大量的错误是发生在输入或输出的边界上。因此针对各种边界情况设计测试用例,可以查出更多的错误。

    选择测试用例的原则:

    一、如果输入条件规定了值的范围,则应该取刚达到这个范围的边界值,以及刚刚超过这个范围边界的值作为测试输入数据;


    二、如果输入条件规定了值的个数,则用最大个数、最小个数、比最大个数多1格、比最小个数少1个的数做为测试数据;

    三、根据规格说明的每一个输出条件,使用规则一;


    四、根据规格说明的每一个输出条件,使用规则二;

    五、如果程序的规格说明给出的输入域或输出域是有序集合(如有序表、顺序文件等),则应选取集合的第一个和最后一个元素作为测试用例;


    六、如果程序用了一个内部结构,应该选取这个内部数据结构的边界值作为测试用例;


    七、分析规格说明,找出其他可能的边界条件。

     


    边界值法举例

    找零钱最佳组合

    假 设 商 店 货 品 价 格 (R) 皆 不 大 於 100 元 ( 且 为 整 数 ) , 若 顾 客 付 款 在 100 元 内 (P) , 求 找 给 顾 客 之 最 少 货币 个(张) 数 ? ( 货 币 面 值 50 元 (N50) , 10 元 (N10) , 5 元 (N5) , 1 元 (N1) 四 种 )


    一、 分 析 输 入 的 情 形 。

    R > 100

    0 < R < = 100


    R <= 0


    P > 100


    R<= P <= 100


    P < R

    二、 分 析 输 出 情 形 。

    N50 = 1

    N50 = 0


    4 > N10 >= 1


    N10 = 0


    N5 = 1


    N5 = 0


    4 > N1 >= 1


    N1 = 0

    三、 分 析 规 格 中 每 一 决 策 点 之 情 形 , 以 RR1, RR2, RR3 表 示 计 算 要 找 50, 10, 5 元 货 币 数 时 之 剩 余 金 额 。 R > 100R <= 0
    P > 100
    P < R
    RR1 >= 50
    RR2 >= 10
    RR3 >= 5

    四、 由 上 述 之 输 入 / 输 出 条 件 组 合 出 可 能 的 情 形 。

    R > 100

    R <= 0


    0 < R <= 100, P > 100
    0 < R <= 100, P < R
    0 < R <= 100, R <= P <= 100, RR = 50
    0 < R <= 100, R <= P <= 100, RR = 49
    0 < R <= 100, R <= P <= 100, RR = 10
    0 < R <= 100, R <= P <= 100, RR = 9
    0 < R <= 100, R <= P <= 100, RR = 5
    0 < R <= 100, R <= P <= 100, RR = 4
    0 < R <= 100, R <= P <= 100, RR = 1
    0 < R <= 100, R <= P <= 100, RR = 0

    五、 为 满 足 以 上 之 各 种 情 形 , 测 试 资 料 设 计 如 下 :

    1. 货品价格 = 101

    2. 货品价格 = 0

    3.货品价格 = -1

    4. 货品价格 = 100, 付款金额 = 101

    5. 货品价格 = 100, 付款金额 = 99

    6. 货品价格 = 50, 付款金额 = 100

    7. 货品价格 = 51, 付款金额 = 100

    8. 货品价格 = 90, 付款金额 = 100

    9. 货品价格 = 91, 付款金额 = 100

    10. 货品价格 = 95, 付款金额 = 100

    11. 货品价格 = 96, 付款金额 = 100

    12. 货品价格 = 99, 付款金额 = 100

    13. 货品价格 = 100, 付款金额 = 100

  • 边界值测试

    2007-03-20 14:11:51

    今天 早上开了个项目总结的会,虽然我没有直接参与这个项目的开发,但是在前期也对这个项目有过一些了解。大家的发言都给我与启发。谢谢 同事们无私地共享自己参与这个项目的经验,自己感觉在边界值测试这方面的理论还是不熟,还需要在复习、复习以便以后能熟练运用。

    边界值分析方法(转贴)

    一.方法简介
    1.定义:边界值分析法就是对输入或输出的边界值进行测试的一种黑盒测试方法。通常边界值分析法是作为对等价类划分法的补充,这种情况下,其测试用例来自等价类的边界。
     

    2.与等价划分的区别
      1)边界值分析不是从某等价类中随便挑一个作为代表,而是使这个等价类的每个边界都要作为测试条件。
      2)边界值分析不仅考虑输入条件,还要考虑输出空间产生的测试情况。

    3.边界值分析方法的考虑:
      长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。
      使用边界值分析方法设计测试用例,首先应确定边界情况。通常输入和输出等价类的边界,就是应着重测试的边界情况。应当选取正好等于,刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据。

    4.常见的边界值
      1)对16-bit 的整数而言 32767 和 -32768 是边界
      2)屏幕上光标在最左上、最右下位置
      3)报表的第一行和最后一行
      4)数组元素的第一个和最后一个
      5)循环的第 0 次、第 1 次和倒数第 2 次、最后一次

    5.边界值分析
      1)边界值分析使用与等价类划分法相同的划分,只是边界值分析假定错误更多地存在于划分的边界上,因此在等价类的边界上以及两侧的情况设计测试用例。
        例:测试计算平方根的函数
            --输入:实数
            --输出:实数
            --规格说明:当输入一个0或比0大的数的时候,返回其正平方根;当输入一个小于0的数时,显示错误信息"平方根非法-输入值小于0"并返回0;库函数Print-Line可以用来输出错误信息。
           
      2)等价类划分:
        I.可以考虑作出如下划分:
          a、输入 (i)<0 和 (ii)>=0
          b、输出 (a)>=0 和 (b) Error
        II.测试用例有两个:
          a、输入4,输出2。对应于 (ii) 和 (a) 。
          b、输入-10,输出0和错误提示。对应于 (i) 和 (b) 。

      3)边界值分析:
        划分(ii)的边界为0和最大正实数;划分(i)的边界为最小负实数和0。由此得到以下测试用例:
        a、输入 {最小负实数}
        b、输入 {绝对值很小的负数}
        c、输入 0
        d、输入 {绝对值很小的正数}
        e、输入 {最大正实数}
       
      4)通常情况下,软件测试所包含的边界检验有几种类型:数字、字符、位置、重量、大小、速度、方位、尺寸、空间等。
      5)相应地,以上类型的边界值应该在:最大/最小、首位/末位、上/下、最快/最慢、最高/最低、  最短/最长、 空/满等情况下。
      6)利用边界值作为测试数据

     
    边界值
    测试用例的设计思路
    字符
    起始-1个字符/结束+1个字符
    假设一个文本输入区域允许输入1个到255个 字符,输入1个和255个字符作为有效等价类;输入0个和256个字符作为无效等价类,这几个数值都属于边界条件值。
    数值
    最小值-1/最大值+1
    假设某软件的数据输入域要求输入5位的数据值,可以使用10000作为最小值、99999作为最大值;然后使用刚好小于5位和大于5位的 数值来作为边界条件。
    空间
    小于空余空间一点/大于满空间一点
    例如在用U盘存储数据时,使用比剩余磁盘空间大一点(几KB)的文件作为边界条件。


      7)内部边界值分析:
        在多数情况下,边界值条件是基于应用程序的功能设计而需要考虑的因素,可以从软件的规格说明或常识中得到,也是最终用户可以很容易发现问题的。然而,在测试用例设计过程中,某些边界值条件是不需要呈现给用户的,或者说用户是很难注意到的,但同时确实属于检验范畴内的边界条件,称为内部边界值条件或子边界值条件。
        内部边界值条件主要有下面几种:
        a)数值的边界值检验:计算机是基于二进制进行工作的,因此,软件的任何数值运算都有一定的范围限制。

    范围或值
    位(bit)
    0 或 1
    字节(byte)
    0 ~ 255
    字(word)
    0~65535(单字)或 0~4294967295(双字)
    千(K)
    1024
    兆(M)
    1048576
    吉(G)
    1073741824

        b)字符的边界值检验:在计算机软件中,字符也是很重要的表示元素,其中ASCII和Unicode是常见的编码方式。下表中列出了一些常用字符对应的ASCII码值。

     

    字符
    ASCII码值
    字符
    ASCII码值
    空 (null)
    0
    A
    65
    空格 (space)
    32
    a
    97
    斜杠 ( / )
    47
    Z
    90
    0
    48
    z
    122
    冒号 ( : )
    58
    单引号 ( ‘ )
    96
    @
    64
     
     


        c)其它边界值检验
       
    6.基于边界值分析方法选择测试用例的原则
      1)如果输入条件规定了值的范围,则应取刚达到这个范围的边界的值,以及刚刚超越这个范围边界的值作为测试输入数据。
        例如,如果程序的规格说明中规定:"重量在10公斤至50公斤范围内的邮件,其邮费计算公式为……"。作为测试用例,我们应取10及50,还应取10.01,49.99,9.99及50.01等。
      2)如果输入条件规定了值的个数,则用最大个数,最小个数,比最小个数少一,比最大个数多一的数作为测试数据。
        比如,一个输入文件应包括1~255个记录,则测试用例可取1和255,还应取0及256等。
      3)将规则1)和2)应用于输出条件,即设计测试用例使输出值达到边界值及其左右的值。
        例如,某程序的规格说明要求计算出"每月保险金扣除额为0至1165.25元",其测试用例可取0.00及1165.24、还可取一0.01及1165.26等。
        再如一程序属于情报检索系统,要求每次"最少显示1条、最多显示4条情报摘要",这时我们应考虑的测试用例包括1和4,还应包括0和5等。
      4)如果程序的规格说明给出的输入域或输出域是有序集合,则应选取集合的第一个元素和最后一个元素作为测试用例。
      5)如果程序中使用了一个内部数据结构,则应当选择这个内部数据结构的边界上的值作为测试用例。
      6)分析规格说明,找出其它可能的边界条件。

    二.实战演习
    1.现有一个学生标准化考试批阅试卷,产生成绩报告的程序。其规格说明如下:程序的输入文件由一些有80个字符的记录组成,如右图所示,所有记录分为3组:

     

     


      ①标题:这一组只有一个记录,其内容为输出成绩报告的名字。
      ②试卷各题标准答案记录:每个记录均在第80个字符处标以数字"2"。该组的第一个记录的第1至第3个字符为题目编号(取值为1一999)。第10至第59个字符给出第1至第50题的答案(每个合法字符表示一个答案)。该组的第2,第3……个记录相应为第51至第100,第101至第150,…题的答案。
      ③每个学生的答卷描述:该组中每个记录的第80个字符均为数字"3"。每个学生的答卷在若干个记录中给出。如甲的首记录第1至第9字符给出学生姓名及学号,第10至第59字符列出的是甲所做的第1至第50题的答案。若试题数超过50,则第2,第3……纪录分别给出他的第51至第100,第101至第150……题的解答。然后是学生乙的答卷记录。
      ④学生人数不超过200,试题数不超过999。
      ⑤程序的输出有4个报告:
        a)按学号排列的成绩单,列出每个学生的成绩、名次。
        b)按学生成绩排序的成绩单。
        c)平均分数及标准偏差的报告。
        d)试题分析报告。按试题号排序,列出各题学生答对的百分比。
      解答:分别考虑输入条件和输出条件,以及边界条件。给出下表所示的输入条件及相应的测试用例。


      输出条件及相应的测试用例表。


     
    2.三角形问题的边界值分析测试用例
    在三角形问题描述中,除了要求边长是整数外,没有给出其它的限制条件。在此,我们将三角形每边边长的取范围值设值为[1, 100] 。
     

    测试用例
    a
    b
    c
    预期输出
    Test1
    Test2
    Test3
    Test4
    Test5
    60
    60
    60
    50
    50
    60
    60
    60
    50
    50
    1
    2
    60
    99
    100
    等腰三角形
    等腰三角形
    等边三角形
    等腰三角形
    非三角形
    Test6
    Test7
    Test8
    Test9
    60
    60
    50
    50
    1
    2
    99
    100
    60
    60
    50
    50
    等腰三角形
    等腰三角形
    等腰三角形
    非三角形
    Test10
    Test11
    Test12
    Test13
    1
    2
    99
    100
    60
    60
    50
    50
    60
    60
    50
    50
    等腰三角形
    等腰三角形
    等腰三角形
    非三角形

     


      
     

    3.NextDate函数的边界值分析测试用例
    在NextDate函数中,隐含规定了变量mouth和变量day的取值范围为1≤mouth≤12和1≤day≤31,并设定变量year的取值范围为1912≤year≤2050 。

    测试用例
    mouth
    day
    year
    预期输出
    Test1
    Test2
    Test3
    Test4
    Test5
    Test6
    Test7
    6
    6
    6
    6
    6
    6
    6
    15
    15
    15
    15
    15
    15
    15
    1911
    1912
    1913
    1975
    2049
    2050
    2051
    1911.6.16
    1912.6.16
    1913.6.16
    1975.6.16
    2049.6.16
    2050.6.16
    2051.6.16
    Test8
    Test9
    Test10
    Test11
    Test12
    Test13
    6
    6
    6
    6
    6
    6
    -1
    1
    2
    30
    31
    32
    2001
    2001
    2001
    2001
    2001
    2001
    day超出[1…31]
    2001.6.2
    2001.6.3
    2001.7.1
    输入日期超界
    day超出[1…31]
    Test14
    Test15
    Test16
    Test17
    Test18
    Test19
    -1
    1
    2
    11
    12
    13
    15
    15
    15
    15
    15
    15
    2001
    2001
    2001
    2001
    2001
    2001
    Mouth超出[1…12]
    2001.1.16
    2001.2.16
    2001.11.16
    2001.12.16
    Mouth超出[1…12]

    转载自:http://blog.csdn.net/vincetest/archive/2007/01/06/1475502.aspx


     

  • 一个小例子

    2007-03-19 17:43:08

    要测试的方法

    public bool IsNumeric(string str)
      {
       if (str == null || str.Length == 0)
        return false;
       System.Text.ASCIIEncoding ascii = new System.Text.ASCIIEncoding();
       byte[] bytestr = ascii.GetBytes(str);
       foreach(byte c in bytestr)
       {
        if (c < 48 || c > 57)
        {
         return false;
        }
       }
       return true;
      }


     }

     

    测试代码

    using System;
    using NUnit.Framework;
    using JWWEB.AD;


    namespace JWWEB
    {
     /// <summary>
     /// H_branchM_Test 的摘要说明。
     /// </summary>
    [TestFixture]
     public class H_branchM_Test
     {
       string aa;
     string bb;
     H_branchM cl=new H_branchM();
     [SetUp]
      public void inite()
      {
          
       aa="aa";
       bb="33";
      }
     [Test]
     public void IsNumber1()
     {  
      Assert.AreEqual(false,cl.IsNumeric(aa));  
      
     }
     [Test]
     public void IsNumber2()
     {  
      Assert.AreEqual(true,cl.IsNumeric(bb));
        
     }
     [Test]
     public void IsNumber3()
     {   string hh="";
      Assert.AreEqual(false,cl.IsNumeric(hh));
        
     }
     [Test]
     public void IsNumber4()
     {
       string hh=null;
      
      Assert.AreEqual(false,cl.IsNumeric(hh));
        
     }
     }
    }
    好久没写代码了,写一段都错误百出,以后的好好恶补一下写代码的能力了。不知道在.net 里面用什么工具来检测测试覆盖率?过几天找找看。

     

  • 221/212>

    数据统计

    • 访问量: 16238
    • 日志数: 25
    • 建立时间: 2007-03-08
    • 更新时间: 2007-10-09

    RSS订阅