本文内容部分来自对官方文档的翻译和理解,部分来源于遇到问题的整理和记录。

mysql-test quick-start:

参考http://dev.mysql.com/doc/mysqltest/2.0/en/writing-tests-quick-start.html

 

运行用例

1、  进到测试目录

shell> cd mysql-version/mysql-test

2、创建测试文件t/test_name.test

3、创建空的结果文件

touch r/test_name.result

4、执行测试

./mysql-test-run.pl test_name

5、假设测试产生了输出文件,此时测试的结果一定是fail的,因为判断用例是否通过是判断运行的输出与结果文件是否一致。失败后会产生一个文件 r/test_name.reject。检查reject文件的内容,如果里面是期望的输出,则将内容拷贝到.result文件中,作为以后判断运行结果是否通过的依据。Mysql-test还提供了一个参数—record实现自动生成result文件的方式

./mysql-test-run.pl --record test_name

6、再次执行测试,结果会是成功的

./mysql-test-run.pl test_name

如果后面不带有任何参数,将运行所有的case,包括上面刚刚加入的用例

 

在测试用例的组织上,建议每个.test文件取合适的长度以包含多个测试点;如果每个测试点都独立为单独的文件,会导致测试执行时间变长,影响效率。

 

为了保持测试用例的独立性,需要避免用例间的互相依赖。当有通用的需求时,例如在多个测试中可能用到同一个表,那么将这个表的定义放在目录 mysq-test/include中,命名 mysql-test/include/create_my_table.inc,并通过source命令在每个case中进行调用。使用inc结尾是习惯做法,并没有特殊要求。调用方法如下:



--source include/create_my_table.inc



每个case中需要保证case结束时将这个表drop掉。

 

测试用例编写的规范或者使用指南:

1、  尽可能避免每行超过80个字符

2、  使用#开头,作为注释

3、  缩进使用空格,避免使用tab

4、  SQL 语句使用相同的风格,包括关键字大写,其它变量、表名、列名等小写

5、  增加合适的注释。特别是文件的开头,注释出测试的目的、可能的引用或者修复的bug编号

6、  一般情况下,mysql-test-run.pl启动自己的Mysql服务来进行测试,除非在启动时指定参数—extern,来说明使用的Mysql服务。为了避免可能的冲突,习惯上表命名使用t1、t2...... 视图命名使用v1、v2。。。。。。

 

一个简单的测试用例的例子:http://dev.mysql.com/doc/mysqltest/2.0/en/writing-tests-sample-test-case.html

 

基于运行效率的考量,mysqltest的测试引擎会使用同一个server来连续的执行不同的测试文件,在运行的过程中会使用同一个database。在case结束时要保证将新建的表以及临时文件等清除掉。一般情况下,在case运行前,也对可能有干扰的表先做清除,例如:


--disable_warnings
 
 
DROP TABLE IF EXISTS t1,t2;
 
 
--enable_warnings


 

Case运行失败的可能原因:

1、  用例文件中的sql是不合法的

2、  产生的结果文件与期望文件diff结果不一致

 

处理期望的错误输出:

在期望有返回错误的前面使用error指令,例如创建一个已经存在的表名时,可以任选下面任一种方式



--error 1050
 
 
--error ER_TABLE_EXISTS_ERROR



其中数字对应错误码,ER_TABLE_EXISTS_ERROR对应错误的逻辑名。这样在mysqltest运行后,会将返回的错误信息一起写入结果文件,这些错误信息就作为期望结果的一部分了。

也可以使用SQLSTATE来指示期望有错误返回,例如与Mysql错误码1050关联的SQLSTATE值是42S01,使用下面的方式,注意编码增加了S前缀:



--error S42S01



在指令error后面是可以加入多个错误码作为参数的,使用逗号分隔即可

错误码及逻辑值的对应关系参考Mysql源代码include目录下的mysqld_error.h 和sql_state.h

 

显示和关闭结果信息

显示影响的结果,指令和结果如下:



--enable_info
 
 
CREATE TABLE t2 (Period SMALLINT);
 
 
affected rows: 0
 
 
INSERT INTO t1 VALUES (9410,9412);
 
 
affected rows: 1
 
 
INSERT INTO t2 VALUES (9410),(9411),(9412),(9413);
 
 
affected rows: 4
 
 
--disable_info



如果不想记录在测试文件中写的sql statements可以通过指令打开enable_query_logdisable_query_log 关闭,如果想控制是否记录执行命令的输出,可以通过执行disable_result_log关闭和enable_result_log打开。

 

处理输出中可能变化的值

某些查询结果列的值,在每次运行后可能返回不同的值,如果我们并不关心这一列具体的值时,可以将它转换为一个常量记录在结果文件中。通过将replace_column写在查询语句之前,例如,第一列可能是变化的值且我们不关心它是什么时:


--replace_column 1 XXX
 
 
SELECT * FROM t1;



也可以同时替换多个列,在后面直接写即可

 

由mysql-test-run.pl向mysqld传递运行参数

1、向mysqld传递两个参数--skip-innodb 和 --key_buffer_size=16384。注意—mysqld需要写两次

mysql-test-run.pl --mysqld=--skip-innodb --mysqld=--key_buffer_size=16384

2、使用--combination传递,效果是连续运行两次,分别使用其中一行的参数传给mysqld。如果只有一行,那么与—mysqld是一样的

mysql-test-run.pl
--combination=--skip-innodb
--combination=--innodb,--innodb-file-per-table

更多示例参考Section 4.12.1, “Controlling the Binary Log Format Used for an Entire Test Run”

 

定义case关联的Mysql Server参数或用法

当测试需要使用指定的命令行参数重启server时,可以定义文件 mysql-test/t/test_name-master.opt,mysql-test-run.pl在执行test_name这个用例时会检查当前server是否含有这些参数,如果没有则使用这些参数重启mysqld

在某些特殊情况下,会有意的让mysqld服务 crash掉,--skip-core-file参数会避免在测试过程中产生core文件

当需要在case执行前执行外部的命令时,将命令写到 t/test_name-master.sh中,它会在启动server前执行。因为需要shell执行脚本,所以在windows环境下会自动跳过。

 

使用include文件简化用例

在include目录下已经保存了很多文件,作为公共的文件,封装了各种复杂的操作,这样在执行用例时可以实现简单的调用,例如当我们想验证是否支持csv类型的存储引擎时,可以在用例文件中增加如下引用:



--source include/have_csv.inc



测试用例中需要确保include的文件存在,否则测试会直接退出。

使用场景:

1、  检查是否支持指定的存储引擎

2、  检查支持的字符集

3、  是否需要debug选项

4、  等待一个条件变成true

5、  控制binlog格式

6、  控制从库服务

可以将include文件看做是一个子程序模块,可以通过设定变量的方式向它传递参数,以及获取它们的返回值。

 

控制binlog格式

如果我们的测试用例rpl.rpl_row*需要在不同的binlog模式(row和statement)下运行,可以通过下面两种方式:

mysql-test-run.pl --suite=rpl --do-test=rpl_row
--combination=--binlog_format=row
--combination=--binlog_format=mixed

或者通过combinations文件的方式,即增加文件suite/rpl/combinations,内容如下:


[row]
 
 
--binlog_format=row
 
 
 
 
 
[mixed]
 
 
--binlog_format=mixed


执行方式:

mysql-test-run.pl --suite=rpl --do-test=row

 

上面的控制方法或是影响运行的全部case,或者是影响suite/rpl目录下的所有case。如果想控制每个case有单独的设置,需要借助include的方式来实现。将case文件中包含如下其中的一行即可:



--source include/have_binlog_format_row.inc
 
 
--source include/have_binlog_format_statement.inc
 
 
--source include/have_binlog_format_mixed.inc



如果是需要支持两种格式,则在下面选择一行:


--source include/have_binlog_format_mixed_or_row.inc
 
 
--source include/have_binlog_format_mixed_or_statement.inc
 
 
--source include/have_binlog_format_row_or_statement.inc


在mtr执行前,mtr会检查系统的binlog格式是否满足source中指定,一直后采取执行case,否则会skip。

如果不包含have_binlog_format_*.inc,则视为支持所有的格式。

 

主从复制相关的用例

http://dev.mysql.com/doc/mysqltest/2.0/en/writing-tests-replication-tests.html

Case文件中只需要添加如下的指令即可:


--source include/master-slave.inc
 
 
在主从间切换:
 
 
connection master;
 
 
connection slave;

屏蔽期望的errors和warnings

测试用例执行完毕后,没有出现错误的情况下,mtr会继续坚持server记录的log,如果发现了任何warning或者error,结果也会是failed。此时我们需要忽略掉一些warnings或者error,因为有些异常是测试输入的条件。文件include/mtr_warnings.sql中,列出了所有需要忽略的warings或者errors,文件中的内容是支持正则表达式的。

也可以通过用例中的指令来屏蔽错误,例如:


--disable_query_log
 
 
call mtr.add_suppression("The table 't[0-9]*' is full");
 
 
--enable_query_log

另一种屏蔽的方式是给mysql-test-run.pl传递参数:--nowarnings

 

测试执行过程中停止Server

http://dev.mysql.com/doc/mysqltest/2.0/en/stopping-server-during-test.html

 

 

通过mtr启动一个mysqld用来调试:

shell> cd mysql-test

shell> ./mysql-test-run.pl --start alias &

shell> ../mysql -S ./var/tmp/mysqld.1.sock -h localhost -u root

使用的配置文件就是默认跑所有case情况下,第一个case使用的配置文件

 

使用参数--start-and-exit的含义:是启动mysqld后,mtr就退出。其它效果含义同—start

 

 

Mysql-test-run术语及说明和语言参考

1、  Command:是mysqltest本身能够识别和执行的输入语句

2、  Statements:是SQL statements,是mysqltest发送给MySQL服务端执行的语句。

3、  Mysqltest启动后,使用的连接名为default与MySQL server连接。用例中通过connect command打开其它连接,使用connection command在多个连接间进行切换。

4、  注释以#开头,除此之外,mysqltest首先把它认为是command去执行,如果是它不认识关键字,则作为statements发送给MySQL server去执行。确认命令的结尾是依赖分隔符的,来区分一行中可能有的多个command,或者多行相连才是一条完整的语句,默认的分隔符就是分号,当然这也是可以通过delimiter command来修改。回车换行并不是作为一条command或者statements结束的标志。当statements中sql开头的keywords也是mysqltest的command时,为了避免歧义,使用以双短横线 “--“开头的方式书写命令。如下两种方式的语义是相同的

--sleep 2


sleep 2;

 

循环语句:


let $1= 10;
 
 
while ($1)
 
 
{

 
 
# execute your statements here
 
 
dec $1;
 
 
}


 

语句之间暂停



sleep 0.2;



 

跳过执行用例

skip [message]
 
 
let $v= 0;
 
 
if (!$v)
 
 
{

 
 
  skip value is zero, skipping test;
 
 
}
 
 
echo This command is never reached;


skip是一条command,后面是输出的skip原因,mtr在打印完message后退出,不再执行测试文件中的后续内容。