交互式测试脚本开发

一个数据库中包含的功能及语法非常庞大,如果是按照语法手动输入测试会非常繁琐且易出错。TCL脚本广泛应用于自动化测试,快速原型开发,脚本编程, GUI等各个方面。例如,Spirent TestCenter就是基于TCL进行网络设备测试的。

expect是Unix系统中用来进行自动化控制和测试的软件工具,应用在交互式软件中如telnet,ftp,Passwd,fsck,rlogin,tip,ssh等等。在deepin下,远程登录就是利用expect实现的。在实际工作中,我们运行命令、脚本或程序时,这些命令、脚本或程序都需要从终端输入某些继续运行的指令,而这些输入都需要人为的手工进行。而利用expect,则可以根据程序的提示,模拟标准输入提供给程序,从而实现自动化交互执行。这就是expect。expect是由tcl语言演变而来的,所以expect脚本的运行需要tcl的支持。安装tcl和expect的步骤略,请自行查找安装方式。

expect基础

基本命令

expect基本命令:

  • send 用于向进程发送字符串

send命令接收一个字符串参数,并将该参数发送到进程。

  • expect 从进程接收字符串

expect命令和send命令相反,expect通常用来等待一个进程的反馈,我们根据进程的反馈,再发送对应的交互命令。

  • spawn 启动新的进程

spawn命令用来启动新的进程,spawn后的send和expect命令都是和使用spawn打开的进程进行交互。

  • interact 允许用户交互

interact命令用的其实不是很多,一般情况下使用spawn、send和expect命令就可以很好的完成我们的任务;但在一些特殊场合下还是需要使用interact命令的,interact命令主要用于退出自动化,进入人工交互。

简单示例

参考下面脚本:

#!/usr/bin/expect

set timeout 30
set host "192.168.1.215"
set username "root"
set password "123456"

spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact

#!/usr/bin/expect 使用expect来解释这个脚本。

set timeout 30 设置超时时间,单位是秒,默认是10秒,这里设置了30秒超时。

set host "192.168.1.215"set username "root"set password "123456" 设置host、username、password变量。

spawn ssh $username@$host spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。它主要的功能是给ssh运行进程加个壳,用来传递交互指令;

expect "*password*" 这里的expect也是expect的一个内部命令,这个命令的意思是判断上次输出结果里是否包含“password”的字符串,如果有则立即返回;否则就等待一段时间后返回,这里等待时长就是前面设置的30秒;

send "$password\r" 当匹配到对应的输出结果时,就发送密码到打开的ssh进程,执行交互动作;

interact 执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。

很简单的expect脚本,就是设定好的用户名、密码登录服务器,实现了类似于xshell记录用户名密码进行自动登录的功能。

但这里包含了expect一个重要的概念,模式-动作。

模式-动作

expect "*password*" {send "$password\r"}即是模式-动作的代表,简单来说就是匹配一个模式,匹配到就执行对应的动作。在这里,就是匹配命令行输出password字符串,如果有,就输入密码。

复杂一点的例子:

expect {
    "password" {
        send "$password\r"
        exp_continue
    }
    eof
    {
        send "eof"
    }
}

其中exp_continue表示循环式匹配,通常匹配之后都会退出语句,但如果有exp_continue则可以不断循环匹配,输入多条命令,简化写法。

传参

很多时候,我们需要传递参数到脚本中,现在通过下面这段代码来看看如何在expect中使用参数:

#!/usr/bin/expect

if {$argc < 3} {
    puts "Usage:cmd <host> <username> <password>"
    exit 1
}

set timeout -1
set host [lindex $argv 0] 
set username [lindex $argv 1]
set password [lindex $argv 2]

spawn ssh $username@$host
expect "*password*" {send "$password\r"}
interact

在expect中,$argc表示参数个数count,而参数值存放在$argv中,比如取第一个参数就是[lindex $argv 0],以此类推。

TCL和expect详细的参考文档请参考Expect and TCL mini reference manual

hubble中的实际测试例子

test.tcl:

#! /usr/bin/env expect -f

source [file join [file dirname $argv0] common.tcl]

start_test "Check that demo says hello properly"

spawn $argv demo

eexpect "Welcome"

eexpect "your changes to data stored in the demo session will not be saved!"

eexpect "Web UI: http:"

eexpect "Server version"
eexpect "Cluster ID"
eexpect "brief introduction"

eexpect root@

eexpect "movr>"
end_test

这个脚本依赖于common.tcl,在common.tcl中定义了一些公用调用proc,例如这个例子中的eexpect,就是在common.tcl中定义的。

proc eexpect {text} {
    expect {
	$text {}
	timeout { handle_timeout $text }
    }
}

eexpect用于匹配字符串,并处理timeout。start_testend_test也是common中定义的输出文本语句。

实际测试时使用 expect -f path/to/test.tcl path/to/hubble

所以在spawn $argv demo时,会运行hubble demo命令。

之后就是校验输出,确定进入的库等信息。

如果是校验具体的SQL,可以添加

send "select count(*) from t.foo;\r"
eexpect "0"

即可校验t.foo表的count值是否符合预期。

计划

持续更新自动化测试部分代码,尽量使测试覆盖的范围更广。