本文内容部分来自对官方文档的翻译和理解,部分来源于遇到问题的整理和记录。
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_log和disable_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后退出,不再执行测试文件中的后续内容。