一般情况下,二进制日志更多的用于数据库的同步,因为二进制日志记录了数据库的所有改变,可以使得SLAVE都可以执行同样的更新,其实二进制日志可以对数据库作一个写入回放,所以也可以用于统计或者即时恢复等其它的目的。
二进制日志仅仅包含可能改变数据库的语句,估计都很容易理解这个,但是那些还没有改变且有可能改变数据库的语句也会记录下来,比如drop table if exists或者是带有WHERE条件的UPDATE和DELETE语句。
一、二进制日志结构
二进制日志是一系列二进制日志事件(又称为binlog事件),其实就是很多文件【包括系列日志文件和一个日志索引文件】共同组成二进制日志,这里每个日志文件称为binlog文件,每个日志文件由很多个日志事件组成,每个日志文件都是以Format_description事件开头并且以日志轮换事件Rotate作为文件结束,如:
mysql> show binlog events in 'master-bin.000003'; +-------------------+-----+-------------+-----------+-------------+---------------------------------------+ | Log_name | Pos | Event_type | Server_id | End_log_pos | Info | +-------------------+-----+-------------+-----------+-------------+---------------------------------------+ | master-bin.000003 | 4 | Format_desc | 1 | 106 | Server ver: 5.1.34-log, Binlog ver: 4 | | master-bin.000003 | 106 | Rotate | 1 | 150 | master-bin.000004;pos=4 | +-------------------+-----+-------------+-----------+-------------+---------------------------------------+ 2 rows in set (0.00 sec) |
Format_description事件包含写日志文件的服务器信息以及日志文件格式,而Rotate事件包含下一个日志文件的文件名及其开始读取的位置。
除了这两个事件以外,日志文件中的其他事件都被分成一个组一个组的形式,在事务存储引擎中,每个组会对应一个事务,而其它有可能是一个语句,总之,日志文件中的事件要么是单个语句,要么是由多条语句组成的事务。
事件类型是有很多种,就是上面的Event_type在实际使用时,会有多个取值,但可以归纳为每个日志事件由三个部分组成:
1、通用头。这部分信息就是所有事件都具备的信息,包含一些基本的信息,比如事件类型以及事件的大小,以上面为例可以从Pos和End_log_pos计算出这条语句的大小。
2、提交头。这部分信息和特定的事件类型有关。
3、事件体。这部分信息存储事件的主要数据,因事件类型不同而不同,例如,事件是Query的时候,存储查询语句。如下:
| master-bin.000004 | 180 | Query | 1 | 297 | use `db_info`; insert into i_node(name,value) values("sql",@value) |
二、记录语句
传统的MySQL采用基于语句的复制,将实际执行的语句及某些和执行相关的信息一起写入二进制日志,然后在从库上重新执行这些语句。由于二进制日志是多个线程往里写入数据,避免两个线程同时更新对于同步来说是很重要的,为此,在事件写入二进制日志之前,需要获得一个互斥锁,然后在事件写完后释放该锁。下面讨论一下哪些数据会被写入二进制日志
2.1 数据操作语言
这通常就是DELETE,INSERT,UPDATE语句。在执行这些语句时,通常是执行语句拥有写锁期间写二进制日志,然后在日志写操作完成之后释放锁,这样保证二进制日志和语句导致的更新信息是一致的。
2.2 数据定义语言
如一些CREATE TABLE 和ALTER TABLE之类的语句。
2.3 查询语句
查询语句的类型是Query事件,这也是最常见的事件,用来存储主库上执行的语句,其实除了实际执行的语句外,这个事件还要包含一些附加的信息。如在写入一行数据中含有AUTO_INCREMENT的字段,我们执行一下写入,然后可以看到日志事件中多了哪些事件:
执行下面语句:
insert into i_node(name,value) values("sql","copy"); |
可以得到多了两条日志事件
| master-bin.000004 | 451 | Intvar | 1 | 479 | INSERT_ID=12 | | master-bin.000004 | 479 | Query | 1 | 596 | use `db_info`; insert into i_node(name,value) values("sql","copy") | +-------------------+-----+-------------+-----------+-------------+-----------------------------------------------------------------------------+ |
其实除此以外,还有其它的一些上下文信息会给当前的执行带来结果的影响,这些都是MySQL执行时需要知道的隐式信息。如:
1、当前数据库。可以看到我执行insert时,并没有执行use db_info这条语句,但是也被日志事件记录下来。因为我在最初执行了,后面MYSQL都采用当前的数据库来执行语句。
2、用户自定义变量的值。如我执行下面两条语句之后
mysql> set @value = 'copy-on-write'; Query OK, 0 rows affected (0.00 sec) mysql> insert into i_node(name,value) values("sql",@value); Query OK, 1 row affected (0.00 sec) |
可以看到此时的日志事件如下:
| master-bin.000004 | 596 | Intvar | 1 | 624 | INSERT_ID=13 | | master-bin.000004 | 624 | User var | 1 | 675 | @`value`=_latin1 0x636F70792D6F6E2D7772697465 COLLATE latin1_swedish_ci | | master-bin.000004 | 675 | Query | 1 | 792 | use `db_info`; insert into i_node(name,value) values("sql",@value) | |
多了一个变量的赋值操作,类型是User var
3、RAND()函数的种子。在执行随机数时,不会记录其随机数,会记录其种子数。
4、当前时间。
5、AUTO_INCREMENT字段的插入值,这个是一个上下文,因为它与前面的行有关。
6、LAST_INSERT_ID函数。
7、线程ID,调用CORRENT_ID函数。
MySQL 提供几种办法以使获取关于数据库和数据库里各种对象(也就是数据库的元数据)的信息,如下:
1、SHOW语句,如SHOW TABLES等等。
2、INFORMATION_SCHEMA数据库里的数据表。
3、命令行程序,如mysqlshow或者是mysqldump。
一、用SHOW语句获取
获取服务器所管理的数据库。
SHOW DATABASES;
查看给定数据库的创建语句。
SHOW CREATE DATABASE db_name;
列出默认数据库里的所有数据表。
SHOW TABLES;
列出给定数据库里的所有数据表。
SHOW TABLES FROM db_name;
查看给定数据表的创建语句。
SHOW CREATE TABLE tbl_name;
查看指定数据表的数据列和索引信息。
SHOW COLUMNS FROM tbl_name; 这个语句和DESC 的输出是一样的。
SHOW INDEX FROM tbl_name;
有几种SHOW语句还可以带有LIKE 'pattern'子句,用来把SHOW语句的输出限定在给定范围,并且允许使用通配符号。
二、从INFORMATION_SCHEMA数据库获取元数据
可以将这个数据库看成一个虚拟的数据库,这个数据库里的数据表是一些由不同的数据库元素数据构成的视图,这个数据库里有以下数据表项:
mysql> show tables from information_schema; +---------------------------------------+ | Tables_in_information_schema | +---------------------------------------+ | CHARACTER_SETS | | COLLATIONS | | COLLATION_CHARACTER_SET_APPLICABILITY | | COLUMNS | | COLUMN_PRIVILEGES | | ENGINES | | EVENTS | | FILES | | GLOBAL_STATUS | | GLOBAL_VARIABLES | | KEY_COLUMN_USAGE | | PARTITIONS | | PLUGINS | | PROCESSLIST | | PROFILING | | REFERENTIAL_CONSTRAINTS | | ROUTINES | | SCHEMATA | | SCHEMA_PRIVILEGES | | SESSION_STATUS | | SESSION_VARIABLES | | STATISTICS | | TABLES | | TABLE_CONSTRAINTS | | TABLE_PRIVILEGES | | TRIGGERS | | USER_PRIVILEGES | | VIEWS | +---------------------------------------+ 28 rows in set (0.01 sec) |
分别对这些列简单的说明。
1、SCHEMATA、TABLES、VIEWS、ROUTIMES、TRIGGERS、EVENTS、PARTITIONS、COLUMNS,表示的信息分别是数据库,数据表,视图,存储例程,触发器,数据库里的事件,数据表分区和数据列的信息,以数据表为例,就是TABLES表,有以下列:
mysql> show columns from INFORMATION_SCHEMA.COLUMNS; +--------------------------+---------------------+------+-----+---------+-------+ | Field | Type | Null | Key | Default | Extra | +--------------------------+---------------------+------+-----+---------+-------+ | TABLE_CATALOG | varchar(512) | YES | | NULL | | | TABLE_SCHEMA | varchar(64) | NO | | | | | TABLE_NAME | varchar(64) | NO | | | | | COLUMN_NAME | varchar(64) | NO | | | | | ORDINAL_POSITION | bigint(21) unsigned | NO | | 0 | | | COLUMN_DEFAULT | longtext | YES | | NULL | | | IS_NULLABLE | varchar(3) | NO | | | | | DATA_TYPE | varchar(64) | NO | | | | | CHARACTER_MAXIMUM_LENGTH | bigint(21) unsigned | YES | | NULL | | | CHARACTER_OCTET_LENGTH | bigint(21) unsigned | YES | | NULL | | | NUMERIC_PRECISION | bigint(21) unsigned | YES | | NULL | | | NUMERIC_SCALE | bigint(21) unsigned | YES | | NULL | | | CHARACTER_SET_NAME | varchar(32) | YES | | NULL | | | COLLATION_NAME | varchar(32) | YES | | NULL | | | COLUMN_TYPE | longtext | NO | | NULL | | | COLUMN_KEY | varchar(3) | NO | | | | | EXTRA | varchar(27) | NO | | | | | PRIVILEGES | varchar(80) | NO | | | | | COLUMN_COMMENT | varchar(255) | NO | | | | +--------------------------+---------------------+------+-----+---------+-------| |
这是我查看一些数据表的记录
mysql> SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA != 'information_schema' and TABLE_SCHEMA!='mysql'\G; *************************** 1. row *************************** TABLE_CATALOG: NULL TABLE_SCHEMA: db_info TABLE_NAME: i_node TABLE_TYPE: BASE TABLE ENGINE: MyISAM VERSION: 10 ROW_FORMAT: Dynamic TABLE_ROWS: 11 AVG_ROW_LENGTH: 21 DATA_LENGTH: 240 MAX_DATA_LENGTH: 281474976710655 INDEX_LENGTH: 2048 DATA_FREE: 0 AUTO_INCREMENT: 16 CREATE_TIME: 2012-09-07 03:07:37 UPDATE_TIME: 2012-09-23 07:57:37 CHECK_TIME: NULL TABLE_COLLATION: latin1_swedish_ci CHECKSUM: NULL CREATE_OPTIONS: TABLE_COMMENT: *************************** 2. row *************************** TABLE_CATALOG: NULL TABLE_SCHEMA: db_info TABLE_NAME: test TABLE_TYPE: BASE TABLE ENGINE: MyISAM VERSION: 10 ROW_FORMAT: Fixed TABLE_ROWS: 3 AVG_ROW_LENGTH: 7 DATA_LENGTH: 21 MAX_DATA_LENGTH: 1970324836974591 INDEX_LENGTH: 1024 DATA_FREE: 0 AUTO_INCREMENT: NULL CREATE_TIME: 2012-09-22 02:25:01 UPDATE_TIME: 2012-09-22 02:37:18 CHECK_TIME: NULL TABLE_COLLATION: latin1_swedish_ci CHECKSUM: NULL CREATE_OPTIONS: TABLE_COMMENT: *************************** 3. row *************************** TABLE_CATALOG: NULL TABLE_SCHEMA: test TABLE_NAME: test TABLE_TYPE: BASE TABLE ENGINE: MyISAM VERSION: 10 ROW_FORMAT: Dynamic TABLE_ROWS: 3 AVG_ROW_LENGTH: 20 DATA_LENGTH: 60 MAX_DATA_LENGTH: 281474976710655 INDEX_LENGTH: 1024 DATA_FREE: 0 AUTO_INCREMENT: NULL CREATE_TIME: 2012-09-07 20:44:41 UPDATE_TIME: 2012-09-07 20:44:41 CHECK_TIME: NULL TABLE_COLLATION: latin1_swedish_ci CHECKSUM: NULL CREATE_OPTIONS: TABLE_COMMENT: 3 rows in set (0.00 sec) |
2、FILES。关于NDB硬盘数据文件的信息。
3、TABLE_CONSTRAINS、KEY_COLUMN_USAGE:关于数据表和数据列上的约束条件的信息,一般唯一化索引和外键都属于这些约束条件。
4、STATISTICS。关于数据表索引特性的信息。
5、REFERENTIAL_CONSTRAINS。关于外键的信息。
6、CHARACTER_SETS、COLLATIONS、COLLATION_CHARACTER_SET_APPLICABILITY。关于所支持的字符集,每种字符集的排序方式、每种排序方式与它的字符集的映射关系信息。
7、ENGINES、PLUGINS。关于存储引擎和服务器插件的信息。
8、USER_PRIVILEGES、SCHEMA_PRIVILEGES、TABLE_PRIVILEGES、COLUMN_PRIVILEGES。全局、数据库、数据表和数据列的权限信息。这些信息分别来自mysql数据库里的user,db,tables_priv,column_priv数据表。
9、PROCESSLIST。在服务器内执行的线程的信息。
10、GLOBAL_VARIABLES、SESSION_VARIABLES、GLOBAL_STATUS、SESSION_STATUS。全局和会话级系统变量和状态变量的值。
三、从命令行获取元数据
先介绍一个命令的使用:mysqlshow。
mysqlshow[选项] [db_name [tbl_name [col_name]]] |
1、如果没有给出数据库,显示所有匹配的数据库。
2、如果没有给出表,显示数据库中所有匹配的表。
3、如果没有给出列,显示表中所有匹配的列和列类型。
说明几个常用的选项信息:
1、--keys。查看某给定数据表里的索引信息。
2、--status。查看某给定数据库里的数据表的描述性信息。如:
[root@localhost ~]# mysqlshow --status db_info Database: db_info +--------+--------+---------+------------+------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ | Name | Engine | Version | Row_format | Rows | Avg_row_length | Data_length | Max_data_length | Index_length | Data_free | Auto_increment | Create_time | Update_time | Check_time | Collation | Checksum | Create_options | Comment | +--------+--------+---------+------------+------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+---------+ | i_node | MyISAM | 10 | Dynamic | 11 | 21 | 240 | 281474976710655 | 2048 | 0 | 16 | 2012-09-07 03:07:37 | 2012-09-23 07:57:37 | | latin1_swedish_ci | | | | | test | MyISAM | 10 | Fixed | 3 | 7 | 21 | 1970324836974591 | 1024 | 0 | | 2012-09-22 02:25:01 | 2012-09-22 02:37:18 | | latin1_swedish_ci | | | | +--------+--------+---------+------------+------+----------------+-------------+------------------+--------------+-----------+----------------+---------------------+---------------------+------------+-------------------+----------+----------------+--------- |
在使用该工具的时候,如果没有默认的数据库服务例程,不要忘了加上--host --user --password甚至是 --socket等信息。
Oracle 与 MySQL 的区别
1、在ORACLE中用select * from all_users显示所有的用户,而在MYSQL中显示所有数据库的命令是show databases。对于我的理解,ORACLE项目来说一个项目就应该有一个用户和其对应的表空间,而MYSQL项目中也应该有个用户和一个库。在ORACLE(db2也一样)中表空间是文件系统中的物理容器的逻辑表示,视图、触发器和存储过程也可以保存在表空间中。而MYSQL并没有使用表空间来进行管理。
2、查询当前所有的表。ORACLE: select * from tab,MYSQL:show tables。
3、改变连接用户(库)。ORACLE:conn 用户名/密码@主机字符串,MYSQL:use 库名。
4、显示当前连接用户(库)。ORACLE:show user,MYSQL:connect。
5、执行外部脚本命令。ORACLE:@a.sql,MYSQL:source a.sql。
比版本 | Personal Oracle 10 | mysql 5.1 |
| | |
默认安装目录 | 可选择 | C:/program files/MYSQL |
各种实用程序所在目录 | 可选择 | C:/program files//BIN |
控制台工具 | SVRMGR.EXE SVRMGR23.EXE | mysqladmin.exe |
数据库启动程序 | 0start73.exe screen | mysqld-shareware.exe |
关闭数据库命令 | ostop73.exe | mysqladmin.exe -u root shutdown |
客户程序 | SQL*Plus | mysql |
启动命令 | c:/orawin95/bin/sqlplus.exe | c:/mysql/bin/mysql.exe |
带用户启动方式 (直接连库方式) | c:/orawin95/bin/sqlplus.exe system/manager@TNS | c:/mysql/bin/mysql.exe test c:/mysql/bin/mysql.exe -u root test |
安装后系统默认用户(库) | sys system scott | mysql test |
显示所有用户(库) | SQL >select * from all_users; | C:/mysql/bin>mysqlshow C:/mysql/bin>mysqlshow --status mysql> show databases; |
退出命令 | SQL> exit SQL> quit | mysql> exit mysql> quit |
改变连接用户(库) | SQL> conn 用户名/密码@主机字符串 | mysql> use 库名 |
查询当前所有的表 | SQL> select * from tab; SQL> select * from cat; | mysql> show tables; c:/mysql/bin>mysqlshow 库名 |
显示当前连接用户(库) | SQL> show user | mysql> connect |
查看帮助 | SQL> ? | mysql> help |
显示表结构 | SQL> desc 表名 SQL> describe 表名 | mysql> desc 表名; mysql> describe 表名; mysql> show columns from 表名; c:/mysql/bin>mysqlshow 库名 表名 |
日期函数 | SQL> select sysdate from dual; | mysql> select now(); mysql> select sysdate(); mysql> select curdate(); mysql> select current_date; mysql> select curtime(); mysql> select current_time;
|
日期格式化 | SQL> select to_char(sysdate,'yyyy-mm-dd') from dual; SQL> select to_char(sysdate,'hh24-mi-ss') from dual;
| mysql> select date_format(now(),'%Y-%m-%d'); mysql> select time_format(now(),'%H-%i-%S');
|
日期函数 (增加一个月) | SQL> select to_char(add_months(to_date('20000101','yyyymmdd'),1),'yyyy-mm-dd') from dual; 结果:2000-02-01 SQL> select to_char(add_months(to_date('20000101','yyyymmdd'),5),'yyyy-mm-dd') from dual; 结果:2000-06-01
| mysql> select date_add('2000-01-01',interval 1 month); 结果:2000-02-01 mysql> select date_add('2000-01-01',interval 5 month); 结果:2000-06-01
|
别名 | SQL> select 1 a from dual; | mysql> select 1 as a; |
字符串截取函数 | SQL> select substr('abcdefg',1,5) from dual; SQL> select substrb('abcdefg',1,5) from dual; 结果:abcde | mysql> select substring('abcdefg',2,3); 结果:bcd mysql> select mid('abcdefg',2,3); 结果:bcd mysql> select substring('abcdefg',2); 结果:bcdefg mysql> select substring('abcdefg' from 2); 结果:bcdefg 另有SUBSTRING_INDEX(str,delim,count)函数 返回从字符串str的第count个出现的分隔符delim之后的子串。 如果count是正数,返回最后的分隔符到左边(从左边数) 的所有字符。 如果count是负数,返回最后的分隔符到右边的所有字符(从右边数)。
|
执行外部脚本命令 | SQL >@a.sql | 1:mysql> source a.sql 2:c:/mysql/bin>mysql <a.sql 3:c:/mysql/bin>mysql 库名 <a.sql |
导入、导出工具 | exp.exe exp73.exe imp.exe imp73.exe | mysqldump.exe mysqlimport.exe |
改表名 | SQL> rename a to b; | mysql> alter table a rename b; |
执行命令 | ;<回车> / r run | ;<回车> go ego |
distinct用法 | SQL> select distinct 列1 from 表1; SQL> select distinct 列1,列2 from 表1; | mysql> select distinct 列1 from 表1; mysql> select distinct 列1,列2 from 表1; |
注释 | -- /*与*/ | # -- /*与*/ |
当作计算器 | SQL> select 1+1 from dual; | mysql> select 1+1; |
限制返回记录条数 | SQL> select * from 表名 where rownum<5; | mysql> select * from 表名 limit 5; |
新建用户(库) | SQL> create user 用户名 identified by 密码; | mysql> create database 库名; |
删用户(库) | SQL> drop user 用户名; | mysql> drop database 库名; |
外连接 | 使用(+) | 使用left join |
查询索引 | SQL> select index_name,table_name from user_indexes; | mysql> show index from 表名 [FROM 库名]; |
通配符 | “%” | “%”和“_” |
SQL语法 | SELECT selection_list 选择哪些列 FROM table_list 从何处选择行 WHERE primary_constraint 行必须满足什么条件 GROUP BY grouping_columns 怎样对结果分组 HAVING secondary_constraint 行必须满足的第二条件 ORDER BY sorting_columns 怎样对结果排序
| SELECT selection_list 选择哪些列 FROM table_list 从何处选择行 WHERE primary_constraint 行必须满足什么条件 GROUP BY grouping_columns 怎样对结果分组 HAVING secondary_constraint 行必须满足的第二条件 ORDER BY sorting_columns 怎样对结果排序 LIMIT count 结果限定
|
最近读了《测试人与敏捷团队的五个约定》,很是赞同。但发现其并没有紧扣敏捷开发测试的特点,这五个约定在传统开发中已经早有实践,也有相关论述。哪么在敏捷开发的测试方面有没有不一样于传统开发测试的并且是有效的实践?
从敏捷团队的组建上来说,敏捷团队并没有要求安排专门的测试人员,甚至于在某些的方法中不建议清楚的区分开发人员角色和测试人员角色。 本文讨论的是已经存在独立测试团队的情况,如何在敏捷开发中进行高效的测试。
实践1:测试保护开发
通过快速的自动化测试跟进开发,保证新增和修改不破坏已经获得的成果。
典型步骤如下:
1、开发人员根据需求,采用TDD,编写代码,实现界面和接口。
2、几乎同步,测试人员编写自动化测试,主要是黑盒自动化测试,也不排除白盒自动化测试。
3、一般保证,代码出来后的第2天,相关的自动化测试代码开发完成。
实践2:成为大敏捷团队的成员
子实践1:参加相关会议,如果是SCRUM,参加SCRUM所有要求的会议。
子实践2:可以阅读和修改最大范围的配置项(比如文档,代码,工作项)
子实践3:一起工作,比如把位子搬到开发人员旁边,如果同时参加多个项目,选择一个较近距离的位子。
说明:这个实践本身的宗旨与传统做法并无根本区别,这里的区别在于程度。
实践3:与定期构建一起执行测试人员的自动化测试用例,或者定期构建包括测试人员的自动化测试。
这里用了”测试人员的自动化测试用例“,也有做法是测试人员和开发人员一起维护自动化测试用例,并没有“测试人员的自动化测试用例“,这里主要说明无论测试人员贡献的自动化测试用例处于何种形式,无论构建是否包括测试人员的自动化测试用例,就是要求自动化测试能与构建为基来执行。
子实践1:维护一套自动化测试环境,可以自动获得最新的测试用例和构建成果
子实践2:测试结果可以自动发布到合适的地方,缺陷得到跟踪管理
实践4:设计更多黑盒手工场景化测试用例,安排更多随机场景测试
关注于局部功能的测试用例在敏捷开发中往往已经被自动化实现了。因此为了发布的测试中,值得设计更多黑盒手工场景化测试用例。选择一些典型场景化测试用例开发为自动化测试用例也是可以的,但是此类测试用例的自动化开发所需工作量较大,要看测试团队的投入和质量目标安排,如果有象微软一样的测试开发工程师,就另当别论了。一般而言,从经济角度出发,黑盒手工场景化测试用例是发现潜在缺陷的有效且经济的手段,如果存在丰富经验的测试人员,随机场景测试也是值得更多采用的。本实践在传统测试中也有,这里要强调的特别之处是可以考虑手工测试全部用场景化测试,大幅减少针对单一功能或局部功能的测试用例。
对测试人员的要求
从以上实践可以看到,测试人员所要掌握的技能有黑盒自动化测试、场景化测试,最好也要常握白盒自动化测试,定期构建和自动测试报告
工具支持
常见的有fit,fitnesse,white,watir,selenium,cruisecontrol,QTP,robot,xUnit系列xFit系列等等
效果和校验
上述的实践是否有效、是否高效,可以观察如下几点:
1、达到发布条件所需的测试轮次是否减少?测试缺陷密度是否减少?
2、获得快速发布的能力,发布工期偏差是否减小?
3、测试所需总的工作量是否在测试团队承受的范围之内,尤其关注测试后期的工作量是否大幅减少,减少的数量是否比在测试前期增加的数量要更大?
如果没有获得正面收益,就需反思了。
摘要:介绍了当前电子商务应用领域的主要结构,以及基于此结构的软件测试技术,采用局部分层测试和系统整体测试相结合的方法是目前最值得介绍堵塞新做法,它既从局部出发,按照软件的三层结构分别对应用系统的每一个层面进行测试,又从整体出发,系统地对整个应用软件进行完整测试,保证了软件开发后的性能要求和用户的可用性。
关键词:电子商务;软件测试
国际互联网的快速增长,使WEB技术对商业、工业、银行、财政、教育、政府和娱乐及我们的工作和生活产生了深远的影响。许多传统的信息和数据库系统正在移植到互联网上,电子商务迅速增长。因此,电子商务应用系统的测试也变得十分重要,它对软件测试提出了新的挑战,要求采用新的测试方法展开软件测试工作。这种对应用系统的测试不但能检查是否满足设计的要求,还需要能测试系统每个层面是否正常,确保系统的整体性能、安全性和可用性满足需要。
一、典型系统结构
随着电子商务的兴起,Web方式的应用系统发展迅速,它将成为电子商务技术领域的主流。在电子商务应用系统中,目前普遍采用的是三层C/S结构,即表示层、业务层和数据层。这种结构使软件测试人员能采用“局部分层测试”和“系统整体测试”想结合的方法,对应用系统进行测试。即先对每一层进行独立的测试,再开展系统整体测试,这样更容易发现应用系统缺陷和错误。如果仅仅依赖系统测试,要确定存在问题的特定部件十分困难。
二、局部分层测试
1、表示层。测试表示层就是检查并应用程序的前端是否存在错误。本层次是应用系统的外表,因此,表示工作对建立一个健壮的、高质量的应用系统至关重要。
(1)内容测试。内容测试用来检验Web应用系统提供信息的正确性、准确性、相关型等人机界面元素,信息的正确性是指信息是可靠的还是误传的,例如,在商品价格列表中,错误的价格可能引起财政问题甚至导致法律纠纷;信息的准确型是指是否有语法或拼写错误。这种测试通常使用一些文字处理软件来进行,例如使用Microsft Word的“拼音与语法检查”功能;信息的相关性是指是否在当前也面可以找到与当前浏览信息相关的信息列表或入口,也就是一般Web站点中所谓“相关文章列表”。此外,还要检查字体类型、屏幕布局、色彩、图形分辨率及其他直接会影响最终用户体验的特性。
(2)Web站点结构。测试Web站点的结构是检查结构上存在的错误,发现无效的连接。链接测试可分为三个方面。首先,测试所有链接是否按指示的安阳确实链接到了该链接的也面;其次,测试所连接的页面是否存在;最后,保证Web应用系统上没有孤立的页面,所谓孤立页面是指没有链接指向该页面,只有知道正确的URL地址才能访问。
(3)用户环境。测试用户平台和浏览器。市场上有很多不同的操作系统平台,最常见的有Windows、Unix、Macintosh、Linux等。Web应用系统的最终用户究竟使用哪一种操作系统,取决于用户系统的配置。这样,就可能会发生兼容型问题,同一个应用可能在某些操作系统下能正常运行,但在另外的操作系统下可能在会运行失败。此外,要测试浏览器。浏览器是Web客户端最核心的构件,来自不同厂商的浏览器对Java、JavaScript、ActiveX、plug-ins或不同的HTML规格有不同的支持。另外,框架和层次结构风格在不同的浏览器中也有不同的显示,甚至根本不显示。操作系统(OS)和浏览器的组合非常多,不仅要测试每一个浏览器的配置,还要测试同一个浏览器的不同版本。
2、业务层。业务层测试的重点是发现应用系统的业务逻辑中的问题。测试业务逻辑层与测试单机程序非常类似,通过测试去检查应用系统是否满足系统性能方面的需求。
(1)性能测试。主要负载测试,即带负载情况下的响应时间和吞吐率。负载测试是为了测量Web系统在某一负载级别上的性能,以保证Web系统在需求范围内能正常工作。负载级别可以是某个时刻同时访问Web系统的用户数量,也可以是在线数据处理的数量。此外,还要进行夜里测试。压力测试是测试系统的限制和故障恢复能力,也就是测试Web应用系统会不会崩溃,在什么情况下会崩溃。
(2)数据验证。测试从用户采集到的数据,通常是以表单形式。当用户给Web应用系统管理员提交信息时,就需要使用表单操作,例如用户注册、登录、信息提交等。在这种情况下,我们必须测试提交操作的完整性,以校验提交给服务器的信息的正确性。如果表单只能接受指定的某些字符,测试时可以跳过这些字符,看系统是否会报错。如果Web应用系统使用Cookies通常用来存储用户信息和用户在某应用系统的操作,当一个用户使用Cookies访问了某一个应用系统时,Web服务器将发送关于用户的信息,把该信息以Cookies的形式存储在客户端计算机上。
(3)业务测试。测试系统的业务处理过程的正确性,其中包括信用卡处理、电子邮件验证以及消费税计算等。电子商务系统必须在全部的时间里正确处理业务,无一例外。因此,要通过测试确保业务处理的正确性。
3、数据层。数据层的测试,主要是指对应系统用于储存和获取信息的数据库管理系统的测试。在Web应用技术中,数据库起着重要的作用,数据库为Web应用系统的管理、运行、查询和实现用户对数据存储的请求等提供空间。在使用了数据库的Web应用系统中,一般情况下,注重数据库操作的响应时间、数据存储的完整和数据库系统的容错。
(1)响应时间。应量化数据操作语言(DML,包括结构化查询语言SQL中INSERT、UPDATE和DELETE)、查询(SELECT)及事物的完成时间。电子商务系统运行速度缓慢会引起客户不满。因此,我们应该积极确保网站能够及时响应用户的请求和操作。在测试数据层的响应时间时,我们要确保单个的数据操作能够快速完成,不至于阻塞其他操作。
(2)数据完整性。验证数据存储适当且正确。所谓数据完整性测试,即在数据库表中发现不准确数据的过程。这项测试与数据确认有所不同,后者在测试业务层时进行。数据确认测试试图发现数据收集中的错误,而数据完整性测试是尽力要在数据存储的方式中发现问题。
(3)容错性和可恢复性。最大化平均故障间隔时间(MTBF),最小平均故障恢复时间(MTTR)。一般来说,数据库操作的一个目标是最大化MTBF,最小化MTTR。
数据库的恢复具有重要意义。可恢复性测试的目标是设计出数据库无法恢复的场景出来。在某些时间,数据库会崩溃,因此须制订一些规程以便快速恢复。恢复计划开始于获得有效的备份,在进行可恢复性测试时,如果无法恢复数据库,那么需要修改备份策略。
三、系统整体测试
1、整体界面。整体界面是整个Web应用系统的页面结构设计,是给用户的一个整体感。例如:当用户浏览Web应用系统时是否感到舒适,能否找到信息所在地方,整个Web应用系统的设计风格的总体效果。
对整体界面的测试过程,其实是一个对最终用户进行调查的过程。一般Web应用系统采取在主页上做一个调查问卷的形式,来得到最终用户的反馈信息。
2、安全性。安全性测试区域主要有:
(1)现在的Web应用系统基本采用先注册,后登录的方式。因此,必须测试有效和无效的用户名和密码,要注意到是否大小写敏感,可以试多少次的限制,是否可以不登录而直接浏览某个页面等。
(2)Web应用系统是否有超时的限制,也就是说,用户登录后在一定时间内(例如15分钟)没有点击任何页面,是否需要重新登录才能正常使用。
(3)为了保证Web应用系统的安全性,日志文件是至关重要的。需要测试相关信息是否写进了日志文件、是否可追踪。
(4)当使用了安全套接字时,还要测试加密是否正确,检查信息的完整性。
3、导航。导航描述了用户在一个页面内操作的方式。在一个页面上放太多的信息往往起到与预期相反的效果。Web应用系统的用户趋向于目的驱动,很快地扫描一个Web应用系统,看是否有满足自己需要的信息,如果没有,就会很快离开。很少有用户愿意花时间去熟悉Web应用系统的结构,因此,Web应用系统导航帮助要尽可能地准确。
导航测试就是检查应用系统的页面结构、导航、菜单、连接的正确性。确保用户知道Web应用系统里面的内容,以及内容所在位置。
四、结束语
在未来电子商务领域,Web软件的测试是一项重要而富有挑战性的工作。基于Web的系统测试与传统的软件测试不同,它不但需要检查和验证是否按照设计的要求运行,而且还要测试系统在不同用户的浏览器的显示是否合适。因此,我们必须为测试复杂的基于Web的系统不断研究新的方法,满足软件开发人员的需要。
先贴本文的重点图:
简单说吧,你们对设计测试用例有什么看法和新的补充嚒?
测试用例的设计这个问题,现在好多时候我们在面对一个功能,比如说一个帮派列表,问我们自己应该怎么测,怎么测试用例的时候你们怎么想?
直接想到的是:测试点->用例
是的,测试点->用例是传统的做法。
你们有没有想过测试点之上其实还能归类呢?或者说至少在测试点同一等级的概念里应该划分一些典型类型来进行测试。
还是拿那个帮派列表来说,所谓的帮派列表。
就是一个面板包含所需列举信息的一个列表。
“我的测试用例都是简单随意的。老毛病”这是近来我经常听到的一句话,测试员A经常唠叨。
1、界面显示是否正常,各种浏览器、分辨率,文字是否显示正常
2、这个数据是否和数据库一致
3、按钮是否正常使用
4、上一页下一页按钮是否正常,能不能正常翻页
5、列表标题是否支持排序,排序功能是否正常
就是比较散乱的测试条例,写得很随意
所以这是个问题,在我看来,测试点这种东西过于偏重了具体测试环境和测试对象,而这个是容易造成测试人员毫无积累的窘境,或者说我们理解的只是狭义的测试点。
列举一下,这也是我最早在以前的博文中提到的基础方法:
传统做法是这样分,功能和数据,首先测功能,各个按钮的功能是否正确,其次看数据。
你们有没有想过测试点之上其实还能归类呢?或者说至少在测试点同一等级的概念里应该划分一些典型类型来进行测试——特别是我们带新人,或者说跳槽去其他公司再次面试(别说没有可能),遇到这种帮会列表问题的测试题目时,我们应该怎么去面试回答呢?
测试点之上或者说跟测试点平等的地位,应该还有一种关系我们是忽略了的(至少现在还没有非常重视),那就是测试类型。
比如:界面测试用例,功能测试用例,大数据测试用例
再比如:正常测试用例,异常测试用例
再比如:异常测试用例里面要有单独的一类测试用例,专门处理各个测试点里的掉线,顶号登陆,下线,离线,这种情况如果我们只是单纯的区分功能和数据,首先测功能,各个按钮的功能是否正确,其次看数据,这种思路很泛,我的意思是这是大道理,并不能由理论转化成实际操作,并不能直接由说转化成如何做,欠缺了些中间的借鉴意义,所以我觉得这方面的话测试类型划分意义更准确些。
希望对大家有所帮助。
延伸阅读——《探索式软件测试》
里面作者在说到测试就用旅游来比喻,他将我们测试的系统分为商业区,娱乐区,破旧区,历史区等,针对不同的区域有着不同的测试方法,思想就和我上面提到的差不多。
各个区域:商业区,历史区,旅游区,娱乐区,旅馆区,破旧区
商业区测试类型:
指南测试法 要求测试人员通过阅读用户手册并严格遵照手册的建议执行操作。
卖点测试法 找到那些最能卖钱的特性进行测试
地标测试法 先选择地标,然后在软件中执行类似于在森林中地标间跳跃的动作
极限测试法 向软件提出很多难以回答的问题。如何使软件发挥到最大程度?哪个特性会使软件运行到其设计极限?哪些输入和数据会耗费软件最多的运算能力?哪些输入可能欺骗它的错误检测例程?如果软件用于产生某些特定输出时,使用哪些输入和内部数据可以不断挑战软件的这种能力?
快递测试法 专注于数据,确认哪些被存储起来的输入数据并“跟随”它们走遍软件。
我这里是粘贴了一部分,毕竟那本书提到的测试法很多,有些就像我说的异常测试,和软件对着干,希望得到更多进步的你可以去看看那本书。
他把我们测试软件比做去一个城市旅游,于是这个测试又叫做漫游测试。
前言:之前一直做的软件质量工作,有过一些经验和一些不太成熟的思路,尽管与现在从事产品运营不同,但无论是内涵还是联系,都是非常紧密的,无论如何,我都会继续关注产品的质量问题。
上周跟一朋友阐述性能中并发的概念,叽里咕噜一大通,完了兴致勃勃地让她总结一下,她说了一句:感觉你研究的东西太初级,并发这种概念,太简单,没什么好说的。我听了差点没晕倒,估计她也晕了,真是失败。
并发真的这么简单?性能真的如我们所理解的那样?
也许并不像我们想象的那么简单,之所以我们去探究这些基本的概念,是因为在实际的工作中,我们发现,很多问题到最后才发现,根源在于概念没有统一,抑或没有理解,而无论作为研发人员,还是顾问、销售人员,我们除了自己理解,还需要与客户交流沟通,因此,深刻理解并能通俗易懂的表达出来是非常重要的。
由于软件性能的范围比较大,我们将选取几个典型的问题进行探究,相关概念的理解与分析将逐步进行公开。
● 如何考察性能
这个问题相信很多同事都了然于心了,基本都有自己的理解,我们也很少接到不懂性能的反馈,但很多人甚至包括客户,都把响应时间或者并发用户作为衡量性能的惟一依据,支持10000并发?性能好!响应时间1秒?性能好!有些时候我们也会接到客户一些要求,让我们哭笑不得,某次一客户就要求我们的产品支持10000并发,有点汗,哈哈。
实际上性能是一项工程,严格地说,性能是在某一个特定环境下,系统所表现出来的最大事务处理能力。如果我们将这个问题细化,性能取决于具体环境,取决于系统架构,取决于软件与服务器的优化等等,也就是,我们所提供的内部测试报告是具备一定的前提的(在一定的网络或硬件环境下),如果我们的架构是包含了10台机器的集群,而客户方提供的却是2台PC机,这种条件下还要求测试结果保持一致,就有点为难了。
尽管性能有很多范围、指标、概念,比如响应时间、吞吐量、并发用户、软硬件负荷等等,但对普通用户来说,并发用户数与响应时间这两个概念还是最为直观与普通,认可度也最高,搞清楚这两个概念非常重要。后面我们会逐步阐述其他概念。
● 理解压力
在谈起并发这个概念之前,我们先来说说压力,对系统而言,性能问题归根到底,都会体现为实实在在的压力。因此,我们一般说的“你这个系统的性能最高能到多少?”,其内在含义指的就是“系统所能承受的最大压力是多少”。
那么压力究竟是什么呢?
我突然想起天天坐的地铁,没有比坐地铁这件事情更便于形容性能与压力了,哈哈。话说我每天在立水桥南上地铁,绝对是考验体力耐力心理素质的事情啊(说岔了)。
我们可以把一班地铁列车看成是一个被测的系统,对于这个系统而言,其压力显而易见,就是列车中所有的人,比如北京地铁5号线,每列车的定员人数是1424人,折合每节车厢237人(当然包括站着的),而最多容纳是1820人,折合每车厢303人,这个总承受人数。
其实就是系统(也就是列车)的最大设计承受压力(也就是吞吐量了),当然,北京地铁比较变态,超员现象比较严重,我每天占用的面积还不超过10平方厘米(脚踮起来了),实际最大负荷估计超过2000了。对列车而言,超过最大负荷是比较危险的,要么是拉不动(这个估计可能性不大),要么人挤坏(君不见每天争吵哀嚎无数)。
如果超出设计负荷值,系统就会存在危险,危险是多方面的,因此,一般的,系统应该具备超出负荷的处理预案,对照到地铁,高峰时期就会进行限流。
搞清楚这个问题后,再来看看常规的系统,就好理解了,系统的压力是什么呢?压力是对被测系统而言的,只要系统在处理事务,就有压力,这种压力不仅仅体现在网络上(数据的吞吐),还体现在服务器上(如CPU、内存等),因此,我们不要混淆了吞吐量与压力的关系,应该这么说,在一些web系统上,吞吐量可以在一定程度上反映系统承受的数据压力。
另外,我们需要清楚,压力不等于性能,压力只是检验性能的一种手段,对一个性能良好的系统,在一定的压力下,应该可以保持正常运转,如果超过负荷,则应该分流或化解压力,这也是我们需要检验的。
● 理解并发
说完压力,我们已经知道,压力其实就是一种作用力,当然,还可以理解为一种量的度量,比如列车的承载数,既然有量,就肯定有速度,承载总量(吞吐量)是一定的,但速度却是变化的,我们早晚高峰的时候去乘地铁,当然是拥挤非常,但如果你晚上11点去做地铁,我可以很高兴地告诉你,你还会有座位!
原因在于,早晚高峰时坐地铁的人多,深夜时坐地铁的人少(这不是废话吗)。我们再来想想,高峰的时候可能同一时间挤进门的人很多,基本上门有多大,同时挤进去的人就能把门给塞满。
那么这个并发(虚拟用户)是什么呢?
并发是有场景条件的,要看我们考察的是什么事情,我们再来想象一下地铁,在整个地铁大厅里(包括列车),有刚刚进站的,有正在买票的,有正在登车的,有坐在车上的,还有闲逛的,这么多人,但对列车有压力的,其实就是已经在车上的这些人(包括挤车的),如果我们考察性能的系统就是列车,很显然,重点关心的就只需要看看车上现有的这些人。
再次强调,并发跟考察的具体场景是有关系的,即并发做什么,并发这个词,原始的翻译是concurrent,意为同时发生的,或同时存在的。至于同时做什么,要看我们定义了,同时在地铁大厅里,同时在地铁上,同时在挤地铁,考察的事情不一样,并发的意义就不一样。
对地铁这个系统而言,每个时间都有新来的人,也有走的人,大家做的事情基本都相同,乘地铁。假定某个时刻地铁大厅中有10000人,检票口候车的有100人,刚刚开走的地铁上乘有2000人,那此时对考察的系统(列车)而言,并发就是2000人,而如果考察的是检票处,则并发为100人,同样,如果考察的系统是地铁大厅,那此时的并发就是10000人。这种并发我们一般称之为“广义并发”。
广义并发有点类似与通常我们所说的在线用户,但存在关键的区别,即并发用户针对的是某一件事务,譬如注册、登录、上传、浏览等,而在线用户是一个很泛的概念,一般包括前面所述的所有事务,可以理解为一个事务集合。
在性能的理论中,还有一个概念,simultaneously,翻译为同步的,当前,为方便计算,我们一般把“同步”理解为“同1秒”,也就是说,这个同步的就是单位时间内发生的数量。也即我们通常所说的“狭义并发”。需要注意的是,实际的测试中经常会遇到被测事务响应时间低于这个1秒的单位时间,此时的并发计算仍需要按1秒计算,具体参见“我们的定义”中的说明。
很多时候,我们(特别是客户)往往搞混了这两个并发的概念。对系统来说,广义的并发实际上是在一个时间内操作事务的虚拟用户,而狭义的并发指的是单位时间内向系统发起请求的虚拟用户,前者是“存在”,后者是“请求”,勿容置疑,压力不仅仅受成功发出请求的用户带来的压力,同时也受“存在”的用户影响。
换种理解方式,并发考察的是系统的处理能力,最多能支持多少用户同时处理某件事务,而不是压力发出端发出的请求。
除此之外,并发作为一个量化的指标,是对应着具体的取值的,因此,很多系统会去寻求最大并发,实际上,我们来回顾5号线的承载力的例子,核定载客1424人,这种情况可能考虑到乘客的感受(还算舒服,站着也算,哈哈)
● 理解我们的定义
在我们已经做过的很多测试中,都有并发这个概念,当然也包括我们很多开发人员,所谓的并发是怎么定义的呢?
客观的说,我们的定义比较接近于“广义并发”,但有所不同。这与我们的考察对象(web系统)、衡量事务(通常我们衡量的都是单个事务,很少把多个事务放在一起处理,原因在于尽量避免事务的耦合性所带来的影响)有关,具体到地铁的例子,如果我们考察的系统指“地铁大厅”,那么我们所谓的并发一般通常指同时进入地铁大厅的人。而如果我们考察的系统指“地铁列车”,那么我们所谓的并发则指同时进入站台的人。
在实际的产品测试中,比如我们在测试IDS登录的时候,如果说,支持800并发,其涵义为“支持800个虚拟用户同时进行登录操作”,需要说明的是,这个同时并非指同一秒,要知道,并发本身是没有单位的。在800并发下的结果如何,要看响应时间,这个问题本文不进行仔细阐述。如有兴趣可以参考相关资料。
测试中,我们也会考虑“狭义并发”的情况,但狭义并发需要考虑到被测系统的入口,比如,假定地铁总共有10个入口且全部开放,每个入口只能容纳1个人进出,则“狭义并发”下最大值就是10?不一定!因为我们还没有考虑速度问题,前面提到,狭义并发的单位是秒,如果每个人通过每个入口的耗时就是1s,则最大“狭义并发”值就是10,如果通过的时间少于1秒呢?还是按1秒算,比如还是这个情景,乘客通过入口的耗时假定为0.1秒,则最大狭义并发就是10/0.1=100了。
简单点说,我们可以这么理解实际工作中的并发,被测的事务总得有人(其实就是虚拟的用户)来做,对吧,同时允许多少用户来做这件事情呢?这个多少用户就是我们需要的并发值。
● 如何估算并发
那么我们如何来估算这个并发值呢?
在此我们需要作出说明,一般我们需要的数据应该来自于实际数据(比如系统日志的记录),这样最可靠,只有当系统新启动且无任何数据参考的时候我们才需要进行估算。
比如我们测试地铁大厅的性能情况,该如何去估算当乘客进入大厅时,地铁大厅的性能呢?下面以笔者经常乘坐的地铁5号线立水桥南站为例进行估算,过程与数据仅供参考。
假定每天从该站乘坐地铁的人数为5万人次,每天的早高峰为7-9点,晚高峰为6-7点,根据8/2原则,80%的乘客(人次)会在高峰期乘坐该站的地铁,则平均每秒到达地铁检票口的人数为(50000×80%)/(3×60×60) = 3.7~=4人,当然这个4人不能作为计算所用的并发值,因为对此时的受压入口检票口来说,4只是每秒到达的压力(即请求)数量,考虑到安检、入口关闭等因素,实际堆积在检票口的人数可能要大于这个数目,假定每个人需要3秒左右才能入站,则实际并发应该为(4人/秒)×3秒=12。当然我们必须指出,这种方法得到的情况并非极端值,因为即使作为早晚高峰,人数的分布也不是平均的(具体情况需要根据实际数据进行分析),但对大部分系统的大部分场景,我们可以用(用户总量/统计时间)×影响因子(一般为3,为经验系数)来进行估算。
实际上,还有一种估算方法,而这种估算方法为国内众多书籍、文章反复转载,其来源与Eric Man Wong在2004年公布的一篇“论文”《Method for Estimating the Number of Concurrent Users》,其核心公式如下:
C=nL/T
其中,C代表在线用户,n代表执行事务的用户总数,L代表每用户的平均在线时间,T为待统计的总时间,依旧以地铁入站的情况进行估算,依旧考虑8/2原则,即n为50000*80%人,T为3小时,L即我们在地铁中停留的时间(从进站到上车),假定为5分钟,因此得到的公式为:
C=(50000人×80%×5min)/3×60min = 1111
并发数是1111,比前面一种算法要高的多,这是为什么呢?
实际上,后面这种统计方法是由一定的局限性与适用范围的,对其统计的每个并发用户而言,每个用户所在线的时间(如上面的5min),并不一定是我们所需要的场景耗时,该5分钟应该是整个大场景(如从进站到离开),而我们通常所使用的场景往往包含了一连贯的子场景,如进站、等待、上车等,因此,如果我们测试的场景是某一个具体的动作,不建议采用这种公式(当然,如果单独为每个动作估算时间也是可以的。)
从本质上来说,两种公式的统计,结果都是一样的,关键取决与统计口径。
极限的问题也是我们需要考虑的,数据的估算往往是一个大的工程,涉及到很多复杂的情况,比如用户的进入与离开,人流异常等,因此我们考虑的多为常规的情况,在一些特殊的情况下,用户的峰值往往要大很多,此时需要去对极限情况下进行估算。
此时的目的在于检查系统的极限承载情况,如列车最大承载2000人,站内极限承载10000人是一样的,超出这个极限,就需要采取一些紧急措施,比如限流(对应到普通的系统,就是设置最大连接数,超出的必须等待)之类。
这种值的计算,不可能给出准确值,可以根据实际情况,协商而定,比如把经验系数更改为5,这种情况下,如果有日志或者统计数据予以支撑,会更加精确。
● 回答客户的疑惑
面对客户,经常需要去解答一些问题,常见的几类疑惑如下:
1、客户坚持要求并发2000,怎么办?
这个问题非常关键,即上面所谓的阐述只是为了让大家对并发等概念有个大体的理
解,但我们的工作重心不是一来就跟客户讲理论,而是合理、有效、迅速地完成项目,因此,特别是一些项目的咨询阶段,如果客户坚持提出达到某个并发要求,我们首先需要看下这个情况产品能否支持,如果不支持,通过修改架构(比如增加服务器,公司的大部分产品都支持集群)来完成,如果还是没法达到要求,我们再来跟客户交流,从客户能理解的方式,从客户的角度去计算并发,最后得到认可就行了。当然,解决这些问题,需要我们对公司的产品性能基本比较了解(可以通过产品的性能测试报告来了解,质保将来会考虑出台所有产品的性能指标集合供参考),如果难度还是很大,可以申请质保的支持。大家一起去解决这个问题。
2、你们的系统能支持10000并发吗?
一些客户经常提出非常高的并发要求,此类客户通常对性能并不了解,或者之前有客户对其做了错误的解释,此时我们需要解释我们测试并发的概念:同时向服务器发出请求的虚拟用户数。(而我们通常会采用严格的方法进行场景测试:即采用集合点的方式进行操作。这种方式也即前面介绍的狭义并发的概念。)
另外,并发值需要考虑实际情况,需要根据实际的需求进行计算,与此同时,并发的影响因素并非仅仅是软件本身,还有网络、架构等等,TRS的产品性能测试往往给出单位机器的性能,用户可以根据这个基础值来构造实际架构。
3、你们的系统怎么才支持200并发?
并发的概念在于同时在处理某一件事情,而且系统一直保持这样的一个强度,并不是说总共只有200人,另外,我们测试的一般是单机,也就是说,如果更好的性能要求,可以通过集群的方式来获得更优的结果,目前TRS的产品基本都支持集群的部署架构。需要注意的是,并发的支持除了软件本身,还受到网络、服务器性能等多方面原因的影响。
4、是否可以使用每秒处理事务来衡量。
性能测试的衡量指标除了响应时间,还有吞吐量、每秒点击数、每秒PV、每秒事务处理能力等,因此我们可以通过多种方式进行衡量,在更大意义上,各个指标间也存在一定的内涵联系,结合起来考虑更能够检查系统的性能。但受制于一些客观原因(如定制),在之前的报告中,指标衡量存在一定的限制。
5、响应时间与并发、压力是什么关系?这么操作的响应怎么才6秒,太慢了,你们的产品性能不行啊!
一般的,一定的并发下将对系统造成一定的压力,而对每个并发(用户)而言,所体现出来的性能多是直观的响应时间,在环境一定的情况下,响应时间越快说明系统性能越好。但此处需要清除一个问题,假定一个用户获取的响应时间是5秒,这5秒都在对系统产生压力吗?
后面这个是一个有趣而有意义的问题,我们知道这个响应时间是从用户发出请求到接收到响应的为止的总耗时,如果我们使用httpwatch之类的工具,可以很清晰的看到时间消耗的分布区间,我们可以把这个问题比作是向墙壁击出一个球,从击出到弹回来的时间即为响应时间。
大家打过壁球吗?打壁球的过程其实就完美的诠释了用户发起请求到接受响应整个过程,可以我们可以把墙壁看作系统,打球者就是用户,球是用户发出的请求,击打一次球包含有三个动作:击出球、球接触墙壁、收到弹回的球。三个过程加起来的总时间就是这个请求(打出一发球)所得到的响应,但很显然,真正对系统产生压力的动作在于接触墙壁的时间,大部分的时间消耗在空中,即球在空中飞行时的时间,而这个飞行时间并不受系统控制,对应到常规系统,就很可能是网络在传输过程中出现了问题。
这个壁球的例子实际上还可以解释一些相关的概念,比如并发就是同时击出多个球,系统(墙壁)所能承受的最大并发压力就是墙壁的面积所能容纳的壁球数量,假定墙壁面积可以容纳1000个球,则墙壁瞬间可以接触的球的数量就是1000个,这个就是狭义并发的概念了,考虑到空中飞行,即将触碰墙壁的球,理论上的广义并发值要高于1000。击球时的力度可以理解为客户端的性能,性能好发球就快,否则就慢,只要系统性能没有达到瓶颈(比如墙壁没有坏),系统的性能是跟客户端呈正比的,即击球速度越快,返回越快。
因此,当遇到客户对响应时间有疑问时,我们需要解释的重点在于,压力在于球接触墙壁的瞬间,但性能测试考核的响应时间确实包含了两次飞行(发送与接受)的时间,而这个时间是受包含服务器性能、网络性能、客户端性能在内的多因素影响的,相信客户可以理解。
● 简单的结论
如果您觉得上面说的东西过于繁琐,以下基本概念可能更适合阅读。
1、并发分为狭义并发与广义并发两种,狭义并发指同一时间点开始做某件事情,广义并发指同一时间段正在做某件事情;
2、并发与被考察的场景是息息相关的,测试中所指的并发一般指同一时间段在做某件事情(被测事务)的用户数,在严格测试的环境下,我们会要求所有用户在同一时间点集合并执行;
3、在线用户与并发用户不是一个概念,在线用户包含了很多非测试事务用户、空闲的客户等,因此不能把在线的用户全计作并发用户,一般的并发用户占在线用户总量在10%~20%左右,当然,这个值仅供参考,实际问题需要实际分析。
4、理论上说并发越大性能越好,但其取决与很多因素,比如网络、服务器数量、服务器性能、系统架构、软硬件优化等,另外,并发的计算需要在需求阶段根据实际情况进行估算,这样得到的结果才是合理的。
5、几个概念的再次说明:
→ 并发用户数:同时在操作被考察事务的用户数
→ 在线用户数:当前被测系统中的活动用户数(包括考察事务与非考察事务)
→ 平均响应时间:每个用户操作事务获得的平均响应时间(算术平均值)
→ 90%响应时间:90%用户平均响应时间在此值范围内(取除去10%极高值后的最大值)
→ 平均事务数:单位时间完成的事务数(如登录、首页读取等)
→ 平均吞吐量:单位时间内的数据传输量
→ 平均点击数:单位时间完成的请求数量
→ PV:某时间段内完成的页面请求数量
软件项目风险是指在软件开发过程中遇到的预算和进度等方面的问题以及这些问题对软件项目的影响。软件项目风险会影响项目计划的实现,如果项目风险变成现实,就有可能影响项目的进度,增加项目的成本,甚至使软件项目不能实现。因此软件项目风险管理是软件质量保障的一项重要内容。
我们根据多年的风险评估经验,在本文中阐述下风险管理的概念以及分类。
风险管理概念
风险管理就是评估风险出现的概率及产生的影响,然后建立一个规划来管理风险。风险管理的主要目标是预防软件项目风险。 如果对项目进行风险管理,就可以最大限度的减少风险的发生。但是,目前国内的软件企业不太关心软件项目的风险管理,结果造成软件项目经常性的延期、超过预 算,甚至失败。成功的项目管理一般都对项目风险进行了良好的管理。因此任何一个系统开发项目都应将风险管理作为软件项目管理的重要内容。
风险分类
软件项目的风险体现在以下四个方面:需求、技术、成本和进度。IT项目开发中常见的风险有如下几类:
1、需求风险
需求已经成为项目基准,但需求还在继续变化;需求定义欠佳,而进一步的定义会扩展项目范畴;添加额外的需求;产品定义含混的部分比预期需要更多的时间;制定需求过程中客户参与不够;缺少有效的需求变化管理过程。
2、计划编制风险
计划、资源和产品定义全凭客户或上层领导口头指令,并且不完全一致;计划是优化的,是“最佳状态”,但计划不现实,只能算是“期望状态”;计划基于使用 特定的小组成员,而那个特定的小组成员其实指望不上;产品规模比估计的要大;完成目标日期提前,但没有相应地调整产品范围或可用资源;涉足不熟悉的产品领 域,花费在设计和实现上的时间比预期的要多。
3、组织和管理风险
仅由管理层或市场人员进行技术决策,导致计划进度缓慢,计划时间延长;低效的项目组结构降低生产率;管理层审查决策的周期比预期的时间长;预算削减,打乱项目计划;缺乏必要的规范,导致工作失误与重复工作;非技术的第三方的工作(预算批准、设备采购批准、法律方面的审查、安全保证等)时间比预期的延长。
4、人员风险
作为先决条件的任务(如培训及其他项目)不能按时完成;开发人员和管理层之间关系不佳,导致决策缓慢,影响全局;缺乏激励措施,士气低下,降低了生产能 力;某些人员需要更多的时间适应还不熟悉的软件工具和环境;项目后期加入新的开发人员,需进行培训并逐渐与现有成员沟通,从而使现有成员的工作效率降低; 由于项目组成员之间发生冲突,导致沟通不畅、设计欠佳、接口出现错误和额外的重复工作;不适应工作的成员没有调离项目组,影响了项目组其他成员的积极性; 没有找到项目急需的具有特定技能的人。
5、开发环境风险
设施未及时到位;设施虽到位,但不配套,如没有电话、网线、办公用品等;设施拥挤、杂乱或者破损;开发工具未及时到位;开发工具不如期望的那样有效,开发人员需要时间创建工作环境或者切换新的工具;新的开发工具的学习期比预期的长,内容繁多。
6、客户风险
客户对于最后交付的产品不满意,要求重新设计和重做;客户的意见未被采纳,造成产品最终无法满足用户的审核;客户没有或不能参与规划、原型和规格阶段的 审核,导致需求不稳定和产品生产周期的变更;客户答复的时间(如回答或澄清与需求相关问题的时间)比预期长;客户提供的组件质量欠佳,导致额外的测试、设计和集成工作,以及额外的客户关系管理工作。
7、产品风险
矫正质量低下的不可接受的产品,需要比预期更多的测试、设计和实现工作;开发额外的不需要的功能,延长了计划进度;严格要求与现有系统兼容,需要进行比 预期更多的测试、设计和实现工作;要求与其他系统或不受本项目组控制的系统相连,导致无法预料的设计、实现和测试工作;在不熟悉或未经检验的软件和硬件环 境中运行所产生的未预料到的问题;开发一种全新的模块将比预期花费更长的时间;依赖正在开发中的技术将延长计划进度。
8、设计和实现风险
设计质量低下,导致重复设计;一些必要的功能无法使用现有的代码和库实现,开发人员必须使用新的库或自行开发新的功能;代码和库的质量低下,导致需要进 行额外的测试,修正错误,或重新制作;过高估计了增强型工具对计划进度的节省量;分别开发的模块无法有效集成,需要重新设计或制作。
9、过程风险
大量的纸面工作导致进程比预期的慢;前期的质量保证行为不真实,导致后期的重复工作;不正规,导致沟通不足,质量欠佳,甚至需重新开发;过于正规,导致 过多耗时于无用的工作;向管理层撰写进程报告占用开发人员的时间比预期的多;风险管理粗心,导致未能发现重大的项目风险。
路漫漫其修远兮,我中心将与大家共同求索。
版权声明:本文出自山东省软件评测中心 张凯丽,51Testing软件测试网原创出品,未经明确的书面许可,任何人或单位不得对本文进行复制、转载或镜像,否则将追究法律责任。
首先在我的职业生涯中,做
性能测试的机会不多,发现性能瓶颈的次数更少,确切的说只有2次。随着大型分布式系统,特别是Web App和
云计算的推广,性能测试的需求会更加迫切。今天我这个半桶水就来谈谈性能测试的话题,欢迎大家一起来讨论。
什么是性能测试?
性能测试是通过自动化的测试工具模拟多种正常、峰值以及异常负载条件来对系统的各项性能指标进行测试。
负载测试和压力测试都属于性能测试,两者可以结合进行。
通过负载测试,确定在各种工作负载下系统的性能,目标是测试当负载逐渐增加时,系统各项性能指标的变化情况。
压力测试是通过确定一个系统的瓶颈或者不能接收的性能点,来获得系统能提供的最大服务级别的测试。
中国软件评测中心将性能测试概括为三个方面:应用在客户端性能的测试、应用在网络上性能的测试和应用在服务器端性能的测试。
通常情况下,三方面有效、合理的结合,可以达到对系统性能全面的分析和瓶颈的预测。
注意这里提到了三个方面,但平常我们往往注意力集中在服务端的性能而忽略了客户端和网络的性能。
下面是我这个半桶水来谈谈一些体会:
一、目的/需求
为什么需要做性能测试或此次做性能测试的目的是什么?
1、新项目/产品,首次发布,需要做基准测试
2、使用中的产品,重构了某个模块/某个模块使用了新的技术,需要一个评估
3、使用中的产品,用户量爆发了,用户量从百万级增加到千万级
4、增加了一个或多个页面,需要对页面的Latency进行一次测试
在测试开始前,需要有准备工作,对此次性能测试的目的做详细了解,确定需要收集哪些数据,关注哪些性能指标。
二、环境部署
性能测试需要一个干净的环境,这个环境包括硬件、网络、操作系统、被测试的系统,数据库。
那在开始前,需要把这个环境部署准备好,最好是能模拟线上的系统,同时这也是一个排除干扰的过程,画出一张架构图。
1、硬件,使用怎样的服务器,理想情况是和生产环境一样的服务器,需要配置负载均衡么
2、网络, 是否需要模拟各种网络,是否需要双网卡,内部网络是否会影响到其他员工正常使用
3、操作系统,windows/linux,是采用默认设置还是已经有参考的设置,哪些操作系统的服务需要关闭,linux中的ulimit如何设置
4、被测试系统,邀请架构师的参与,系统使用怎么样的架构,是否使用了Web Server——IIS/Apache/Tomat,他们的最优配置是怎么样的
5、数据库,站内搜索数据库是否和订单数据库分开,数据库是否有缓存,数据库是否使用主从式
三、场景和负载模式
此次性能测试需要模拟怎样的场景:
1、购物网站秒杀活动,使用恒负载模式,设定集合点,用户并发
2、系统正常的使用,从每天的监控系统中分析,例如看到购物高峰是中午,使用单步负载模式(Ram-up/down),每间隔时间内用户增加多少,到购物高峰时间是恒负载,过了高峰后用户开始减少
3、系统改版,使用基于目标的负载模式,根据历史数据设定目标,或例如设定CPU/Memory最大到85%
确定好了场景和负载模式,才能正确的生成用例/脚本。
四、性能指标
此次性能测试需要收集哪些性能指标和数据:
1、CPU使用率
2、Memory使用率
3、QPS
4、响应时间
5、网络IO
6、文件IO
7、数据库IO
8、最大支持用户数
以上指标并不是都要收集,要根据具体的场景来决定。
五、性能测试工具
提到性能测试,很多测试人的第一概念就是工具,比如商业流行的Loadrunner,开源流行的Jmeter,但是很少人注重上面提到的四点, 所谓“磨刀不误砍材工”,没有上面的设计分析,仅仅使用工具跑出结果是无法分析出性能的瓶颈,不可靠的数据结果会大大增加排查工作,这些数据往往会受到很 多质疑。
工具的使用:
参数化
Loadrunner选择哪个协议
Loadrunner的关联
Loadrunner的Controller/Agent
Jmeter的Remote testing
工具的使用技能仅仅是性能测试里的一小部分,切不可只关注工具使用。
是否每次的性能测试都需要用上大型的工具呢,某个页面的响应时间是否可以使用其他轻量的工具,例如一些浏览器插件Httpwatch,Yahoo YSlow,Google speed tracer;
是否可以自己写些有针对性的小工具,根据实际情况定义出真实的Page load time,而不仅仅是服务器的响应时间。
六、数据收集与分析
性能测试的最终目的是通过数据收集分析出系统是否存在瓶颈,所以数据收集和分析是一个很重要的过程。
分析的过程需要团队成员的参与,例如架构师、DBA、开发人员,是一个长期的过程,通过调整测试脚本,生成不同的数据对比。
七、我所发现的2次问题
1、双网卡问题,一个新改版的项目,上线后在峰值的时候总有机器崩溃或性能大幅下降,最后发现是服务器只使用了单网卡,这个明显就是上面提到的排除干扰没做好(配置没有检查),这次性能测试是失败的。
2、子进程崩溃,64位系统基准测试,通过与团队成员的不断沟通,排除各种设置干扰、确定硬件和软件配置、加入profile工具,与32位系统的对比。
八、后续优化
性能测试仅仅是个开始,性能测试最终目的是发现和解决系统的瓶颈,这就涉及到优化,而优化的过程往往在系统设计阶段就需要考虑。
1、异步获取数据
2、建立缓存
3、分布式
4、文件分解
九、推荐
1、基于用户体验的性能测试,User Experience, Not Metrics
更贴近用户使用场景的性能测试,里面使用的工具主要是IBM的Rational TestStudio
http://www.cnblogs.com/mayingbao/archive/2008/04/11/1148510.html
2、软件性能测试过程详解与案例剖析(第二版)
3、要做好性能测试,该掌握些什么?
http://www.51testing.com/html/23/n-92923.html
http://www.51testing.com/html/93/category-catid-93.html
软件测试用例质量的评估,可以考虑下面3个方面的因素:
第一,根据测试用例的形式评估其质量,主要包括:
1)测试用例与需求规格说明中需求条目的可追溯性,例如:我们要求每个需求条目至少有1个测试用例与之对应。目的是为了评估测试的需求覆盖率,以及分析需求发生变更的时候,对测试修改工作的影响程度;
2)测试用例有无明确的期望结果。通常来说,测试用例的每个执行步骤,都应该明确描述期望的结果,以保证测试人员可以与测试实际结果进行比较,并分析是否需要提交缺陷报告,或者修改测试用例。
3)是否满足公司内部定义的测试用例模板。例如:每个公司都可能定义了测试用例模板,比如定义了“测试类型”,要求每个测试用例和测试类型进行关联,并要求每个功能的测试用例需要覆盖所有的测试类型,例如:可移植性、互操作性、稳定性等。
第二,根据测试用例覆盖率评估其质量,主要包括:
1)需求的覆盖率,例如:我们主要负责系统测试级别,因此测试用例的需求覆盖率要求必须达到100%。
2)质量特性的覆盖率,例如:我们在测试用例模板中采用测试类型的概念,要求每个功能的测试用例,必须100%覆盖所有的测试类型。而测试类型的定义,参考了ISO 9126质量模型,以前缺陷的分析,需求条目的分析等。
3)测试平台的覆盖率,例如:针对我们目前的通信产品,每个功能都需要在不同平台上运行,例如:不同的网元类型、接口类型、业务类型等。测试用例的对这些平台的覆盖率,也要求达到100%。
第三,根据测试用例的有效性评估其质量,主要包括:
1)测试用例的缺陷发现率,我们采用的计算方法是“系统测试发现的缺陷数目除以执行的测试用例数目,而得到的百分比”。
2)脚本化测试的缺陷发现率,我们采用的计算方法是“根据测试用例步骤发现的缺陷数目/总发现的缺陷数目,得到的百分比”。假如这个百分比很低,说明设计的测试用例有效性方面比较差,而通过探索性测试发现的缺陷比例更高。
3)遗漏到用户现场的缺陷率,我们采用的计算方法是“6个月内用户现场反馈的缺陷数目,除以系统测试级别发现的缺陷数目与6个月内用户现场反馈的缺陷数目之后,得到的百分比”。
每个公司和测试团队在评估测试用例质量方面会存在不同的度量指标,基本的要求是这些度量指标简单容易收集,并且有利于改进测试过程和测试团队的测试能力,但切记不会针对测试人员个人的能力与绩效的评估。