如何在测试脚本中与文件和环境交互

除了Squish提供的与测试相关的功能外,测试脚本还可以使用脚本语言自身提供的本地功能(包括标准库)。在本小节中,我们将展示如何使用本地功能从外部文件读取数据、将数据写入外部文件、检查外部文件是否存在以及删除外部文件。此外,我们还将了解如何比较两个外部文件,以及如何读取脚本运行时设置的环循变量。

Python专用

Python示例没有展示任何 import 语句,但这些当然在非全局函数使用时是必需的。在定义 main 函数之前应执行 import 语句,下面展示的足以满足本节示例。

import codecs, filecmp, os, subprocess, sys

Perl专用

Perl示例中没有展示任何 use 语句,但这些当然在非全局函数使用时是必需的。应在定义 main 函数之前执行 use 语句,下面展示的足以满足本节示例。

use File::Basename;
use File::Spec;

如何在测试脚本中与外部文件交互

在这里,我们将了解如何从外部文件读取数据、将数据写入外部文件、检查外部文件是否存在以及删除外部文件。

如何从外部文件读取数据

读取外部文件需要获取其完整的文件名(包括路径),然后以脚本语言支持的常规方式读取文件。例如

    infile = findFile("testdata", "before.csv")
    infile = infile.replace("/", os.sep)
    test.log("Reading %s" % infile)
    file = codecs.open(infile, "r", "utf-8")
    lines = []
    for line in file:
        lines.append(line)
    file.close()
    test.verify(len(lines) == 13)
    infile = findFile("testdata", "before.csv");
    infile = infile.replace(/[\/]/g, File.separator);
    test.log("Reading " + infile);
    file = File.open(infile, "r");
    var lines = [];
    var i = 0;
    while (true) {
        var line = file.readln();
        if (line == null)
            break;
        lines[i++] = line;
    }
    file.close();
    test.verify(lines.length == 13);
    my $sep = File::Spec->rootdir();

    # Load data from an external file
    my $infile = findFile("testdata", "before.csv");
    $infile =~ s,/,$sep,g;
    test::log("Reading $infile");
    open(FILE, "<:encoding(UTF-8)", $infile) or test::fail("Failed to read $infile");
    my @lines = <FILE>;
    close(FILE);
    test::verify(scalar(@lines) == 13);
    infile = natify(findFile("testdata", "before.csv"))
    Test.log("Reading %s" % infile)
    lines = []
    File.open(infile, "r:utf-8") do |file|
        file.each {|line| lines << line}
    end
    Test.verify(lines.length == 13)
    set infile [file nativename [findFile "testdata" "before.csv"]]
    test log "Reading $infile"
    set fh [open $infile]
    set text [read $fh]
    close $fh
    set text [string trimright $text]
    set lines [split $text "\n"]
    test compare [llength $lines] 13

在此,我们读取了一个名称为 before.csv 的文件,该文件位于套件(或测试用例)的 testdata 目录中。该文件是一个使用UTF-8编码的文本文件。我们打开文件并将其逐行读取到一个列表(或数组)中的行,或者将它们拆分成字符串,具体取决于脚本语言。最后,我们检查是否正好读取了我们预期的行数。

Squish在所有平台上使用Unix样式的路径分隔符,但由于我们希望向用户显示路径(使用 test.log(message) 函数),因此我们将这些替换为适合平台的路径分隔符(例如,在Windows上是"\")。

JavaScript没有对文件处理或操作系统交互提供本地支持,因此Squish提供了 File 对象OS 对象 来填补这些空白。

如何将数据写入外部文件

写入外部文件 просто означает создание файлаимени, открытие его для записи и写入数据,按照脚本语言支持的常规方式。例如

    outfile = os.path.join(os.getcwd(), os.path.basename(infile) + ".tmp")
    outfile = outfile.replace("/", os.sep)
    test.log("Writing %s" % outfile)
    file = codecs.open(outfile, "w", "utf-8")
    for line in lines:
        file.write(line)
    file.close()
    outfile = infile + ".tmp";
    var i = outfile.lastIndexOf(File.separator);
    if (i > -1)
        outfile = outfile.substr(i + 1);
    outfile = OS.cwd().replace(/[\/]/g, File.separator) + File.separator + outfile;
    test.log("Writing " + outfile);
    file = File.open(outfile, "w")
    for (var i in lines)
        file.write(lines[i] + "\n");
    file.close();
    $outfile =~ s,/,$sep,g;
    test::log("Writing $outfile");
    open(FILE, ">:encoding(UTF-8)", $outfile) or test::fail("Failed to write $outfile");
    print FILE @lines;
    close(FILE);
    outfile = natify(File.join(Dir.getwd, File.basename(infile) + ".tmp"))
    Test.log("Writing %s" % outfile)
    File.open(outfile, "w:utf-8") do |file|
        lines.each {|line| file.write(line)}
    end
    set outfile [file nativename [file join [pwd] [file tail "$infile.tmp"]]]
    test log "Writing $outfile"
    set fh [open $outfile "w"]
    foreach line $lines {
        puts $fh $line
    }
    close $fh

在此,我们写入一个与读取的文件具有相同基本名的文件,但附加 .tmp(例如,before.csv.tmp),并将其保存到脚本的当前工作目录中。由于我们写入的正是我们读取的数据,因此此文件与原始文件应完全相同。(我们将在后面的子节中了解如何检查这一点。)

正如我们在读取文件时所做的,我们将Unix风格的路径分隔符替换成适用于平台的正确路径分隔符。这只是为了输出到test.log(message) 函数;如果未向用户显示文件名,无论平台如何,我们都可以安全地使用Unix路径分隔符。

如何检查外部文件的存在

以下是一个示例,检查两个文件:第一个文件预期存在,第二个文件不期望存在。

    test.verify(os.path.exists(infile), "infile correctly present")
    test.verify(not os.path.exists(outfile), "outfile sucessfully deleted")
    test.verify(File.exists(infile), "infile correctly present");
    test.verify(!File.exists(outfile), "outfile sucessfully deleted");
    test::verify(-e $infile, "infile correctly present");
    test::verify(!-e $outfile, "outfile sucessfully deleted");
    Test.verify(File.exist?(infile), "infile correctly present")
    Test.verify(!File.exist?(outfile), "outfile sucessfully deleted")
    test verify [file exists $infile] "infile correctly present"
    test verify [expr ![file exists $outfile]] "outfile sucessfully deleted"

我们使用了Boolean test.verify(condition) 函数的两种参数形式,以提供比“表达式为真”更详细的有用信息。

如何删除外部文件

删除外部文件很容易,但不能撤销。

    os.remove(outfile)
    File.remove(outfile);
    unlink $outfile;
    File.delete(outfile)
    file delete $outfile

随后调用Boolean test.verify(condition) 函数,并结合存在性测试,以检查是否已按预期删除文件。

如何在测试脚本中比较外部文件

要比较两个外部文件,最简单的方法是使用Comparing Files Squish API,但也可能使用原生的脚本语言功能。不应需要使用像 difffc 这样的外部程序。

    # Compare using Squish API:
    test.compareTextFiles(infile, outfile)

    # Compare using Python API:
    test.verify(filecmp.cmp(infile, outfile, False),
        "infile and outfile equal according to filecmp library")
    // Compare two external files:
    test.compareTextFiles(infile, outfile)
    # Compare two external files
    test::compareTextFiles($infile, $outfile);
    # Compare two external files
    Test.compareTextFiles(infile, outfile)
    # Compare two external files
    test compareTextFiles $infile $outfile

我们必须让我们的脚本考虑到,我们在Windows上使用fc程序,在其他平台上使用diff程序。幸运的是,这两个程序表现出相同的行为:如果两个文件相同,它们向操作系统返回0(0是程序的传统“成功”值);如果两个文件不同,它们返回1。(如果它们遇到的命令行命令中有错误,可能会返回其他值,例如2。)

注意:正确使用平台的正确路径分隔符是至关重要的。我们还对文件名进行了引号标注,除了Tcl示例外,以防它们或它们的路径包含空格,这在Windows上很常见。

Python专用

Python程序员可以通过利用Python标准库的filecmp模块,避免使用外部程序,并避免将整个文件加载到内存中的低效方法。这把比较两个文件简化为一条语句。

    test.verify(filecmp.cmp(infile, outfile, False),
        "infile and outfile equal according to filecmp library")

函数 filecmp.cmp 返回一个具有True的布尔值,表示文件是相同的。第三个参数应始终为False,以避免任何假阳性风险。

如何在测试脚本中读取环境变量

以下是如何在测试脚本运行时读取一些可能设置的具体环境变量的示例。

    for key in ("HOME", "PATH", "MY_ENV_VAR"):
        test.log("%s = %s" % (key, os.environ.get(key)))
    var keys = ["HOME", "PATH", "MY_ENV_VAR"];
    for (i in keys)
        test.log(keys[i] + " = " + OS.getenv(keys[i]));
    for my $key ("HOME", "PATH", "MY_ENV_VAR") {
        test::log("$key = $ENV{$key}");
    }
    ENV.each {|key, value| Test.log("#{key} = #{value}") }
    global env
    foreach key {"HOME" "PATH" "MY_ENV_VAR"} {
        set value ""
        if {[catch {set value $env($key)}]} {
            # do nothing for missing key: empty default value is fine
        }
        test log "$key = $value"
    }

如果你使用shell脚本或批处理文件作为你的应用程序,你可以轻松地设置一些测试套件特定的环境变量,然后使用这里显示的技术,在测试脚本中访问它们。见Shell Scripts and .bat-Files as AUT。)测试脚本没有访问应用程序的环境变量,例如在Test Suite Settings view的“环境”部分中设置的变量。

对于Python,使用dict.get方法确保我们获取的是缺失键的None值而不是异常。类似地,对于Tcl,我们通过捕获查找的键缺失时出现的异常来实现相同的效果。对于JavaScript和Perl,缺失键的值是无害的空值,打印出来的是空字符串。

©2024 Qt公司版权所有。包含在此处的文档贡献均为各自所有者的版权。
提供的文档根据自由软件基金会发布的版本1.3 GNU自由文档许可证 的条款进行许可。
Qt及其相关标志是芬兰和/或全世界Qt公司的商标。所有其他商标均为各自所有者的财产。