重定向 tcltest 的测试结果

Redirect test results for tcltest

我喜欢在日常测试任务中使用 tcltest。但是我只能在控制台中看到测试结果,所以在每次测试后 运行 我需要切换到那个控制台,才能找到结果。 根据 tcltest 文档,有选项 outputChannel。此选项允许将测试结果重定向到管道或通道,然后显示在我想要的任何地方。 所以我尝试创建这个频道:

set logger [ open "|bash -c \"while true;do sleep 1; while read mess;do  debug=\\"$debug \n $mess\\";done; if \\[\\[ $debug != \\"\\"  \\]\\];then notify-send $debug; debug=\\"\\";fi; done \" " r+]

接下来我像这样配置 tcltest:

configure  -singleproc 1 -verbose t -match ** -outputChannel $logger

然后我尝试在我的频道中发送测试消息:

puts $logger  "Test message 1st line \n test message 2 line"

此脚本有效,但没有显示测试消息,并且通知中没有 tcltest 输出。 我如何创建我的记录器频道??

这似乎是一个相当复杂的脚本。有了这样的事情,分阶段进行会使生活变得容易得多。第一部分是将 Bash 脚本放在大括号中并将其存储在变量中:

set notifySendScript {
    while true; do
        sleep 1
        while read mess; do
            sleep 1
            debug="$debug\n$mess"
        done
        if [[ $debug != "" ]]; then
            notify-send $debug
            debug=""
        fi
    done
}

然后你可以 运行 你的脚本更简单并且更清楚发生了什么(我已经切换到 list 这样它会自动为我们引用):

set logger [ open [list |bash -c $notifySendScript] r+]
puts $logger "aaaaaaaa\n bbbbbbb"

现在我们已经将这些部分分开,我们可以看到您的 bash 脚本中存在问题。特别是,它重复地从标准输入读取(由于循环)直到它获得 EOF,您的代码永远不会发送它,因为它没有 close 管道。更有趣的是,它将它放在一个循环中,这样您的代码将在 EOF 之后继续尝试从标准输入中重复读取 ,这不太可能是您想要的。还有其他问题(例如,不从那个 read-write 管道读取)但我认为最大的问题是你的代码在不需要的时候是一个可怕的 one-liner,那是隐藏的反斜杠墙和不可读性背后​​的所有问题。我强烈建议尝试使 sub-scripts 更整洁(作为单独的文件或至少作为 braced 部分,例如我上面所做的),因为这会阻止你发疯。

由于您试图将大量输出流重定向到它,因此您需要一个更智能的脚本:

set script {
    while read mess; do
        while read -t 1 tail && [ -n $tail ]; do
            mess=`printf '%s\n%s' $mess $tail`
        done
        if [ -n $mess ]; then
            notify-send $mess
        fi
    done
}

set pipeline [open [list |bash -c $script] "w"]
# This could also be an issue; want line buffering because that's what the
# bash script expects, and the default is full buffering (as for *all* channels)
fconfigure $pipeline -buffering line

# Demonstration
puts $pipeline "aaaaaaaa\nbbbbbbb"
after 5000
puts $pipeline "cccccccc\nddddddd"
after 5000
close $pipeline

诀窍是我使用 -t 选项(用于超时)到 read 但仅用于累积额外行的内部循环。此外,它将空行视为发送消息的借口。最后,外层循环将在收到 EOF 时终止。这对于让您正确关闭整个系统很重要。


存在的另一个问题(在测试中比在部署 IMO 时更严重)是它是管道中的 line-oriented 脚本,具有默认缓冲,即 完全 缓冲。我答案第二部分的 fconfigure 是如何解决的;它让您告诉 Tcl 在每一行准备就绪后立即将其发送到管道实现,而不是等待完整的 4–8 kB 数据。

您可能想简化设置并继续使用 Tcl?使用 Tcl 的通道转换重定向 stdout(由 tcltest 在幕后使用)是一个方便的选择;之前已经介绍过 here

此主题有多种变体,但您可能希望通过以下方式开始:

第 1 步:定义通道拦截器

oo::class create TcltestNotifier {
    variable buffer
    method initialize {handle mode} {
        if {$mode ne "write"} {error "can't handle reading"}
        return {finalize initialize write}
    }
    method finalize {handle} {
        # NOOP
    }

    method write {handle bytes} {
        append buffer $bytes
        return $bytes
    }

    method report {} {
        # sanitize the tcltest report for the notifier
        set buffer [string map {\" \\"} $buffer]
        # dispatch to notifier (Mac OS X, change to your needs/ OS)
        append cmd "display notification \"$buffer\"" " "
        append cmd "with title \"Tcltest notification\""
        exec osascript -e $cmd
    }
}

上面的代码片段是从 Donal.

直接导出/窃取的

第 2 步:在您的 tcltest 套件

周围使用 stdout 注册拦截器
package req tcltest
namespace import ::tcltest::*

set tn [TcltestNotifier new]
chan push stdout $tn

test mytest-0.1 "Fails!" -body {
    BARF!;
} -result "?"

chan pop stdout
$tn report

一些评论

  • 您可以改变粒度,为每个输出行请求通知而不是测试报告(然后您必须在 write 方法中发送给您的通知程序)。但我怀疑这是否有意义。
  • 该示例是在 Mac OS X (osascript) 上构建的 运行,您必须将其修改为您的 *nix 工具。