作为在线考试应用程序的一部分,我们需要自动评估学生编写的 LaTeX 脚本。本质上,应该根据一组测试用例评估脚本,如果脚本通过,则所有测试用例都应返回通过 (true),否则应返回错误消息,以便学生可以重试该问题。
我们遇到了qstest
,但我想知道是否有更好的解决方案,可以轻松高效地应用于 Web 应用程序。该 Web 应用程序是使用 Django 开发的。
答案1
使用多种语言进行测试断言和您在问题中提到的测试用例。 中的断言LaTeX
可以采用以下一般形式:
\def\test#1{\def\res{#1}\ifx\foo\res\else\ERROR\fi}
或者只返回“通过”或“失败”。对于较长的测试用例,我倾向于后者,而且如果对结果进行颜色编码,很容易发现错误。
代码可以根据含义简单判断真假
\newcommand\assert[2][]{%
\ttfamily
\def\result{#2}
\ifx\foo\result\textcolor{green}{Passed}%
\else \textcolor{red}{Failed}\fi
\space Test:\,\stepcounter{tst}\thetst
\detokenize{#1}
\par}
或检查事物是否已经定义(有时很棘手)。
% Checks if defined can be unreliable
\newcommand\assertdef[2][]{
\ttfamily
\ifdefined#2\textcolor{green}{Passed}%
\else \textcolor{red}{Failed}\fi
\space Test:\,\stepcounter{tst}\thetst
\detokenize{#1}
\par
}
下面的 MWE 示例测试了一些定点算法和一些Lisp 遗迹来自 LaTeX 内核并生成上图的输出:
\documentclass{article}
\usepackage{xcolor,fp}
\parindent0pt
\makeatletter
\newcounter{tst}
\setcounter{tst}{9}
% asserts true on meaning
\newcommand\assert[2][]{%
\ttfamily
\def\result{#2}
\ifx\test\result\textcolor{green}{Passed}%
\else \textcolor{red}{Failed}\fi
\space Test:\,\stepcounter{tst}\thetst
\detokenize{#1}
\par}
% Checks if defined can be unreliable
\newcommand\assertdef[2][]{
\ttfamily
\ifdefined#2\textcolor{green}{Passed}%
\else \textcolor{red}{Failed}\fi
\space Test:\,\stepcounter{tst}\thetst
\detokenize{#1}
\par
}
\begin{document}
\section{\jobname\\ \today}
\edef\test{\@car 123\@nil}\assert[\@car 123\@nil==1]{1}
\edef\test{\@car{1}23\@nil} \assert[\@car {1}23\@nil==1]{1}
\edef\test{\@car {123}{456}{7}\@nil} \assert{123}
\edef\test{\@carcube1234567\@nil}\assert{123}
\edef\test{\@cdr 123\@nil} \assert{23}
\edef\test{\@cdr {134}{x}\@nil}\assert{x}
\edef\test{\@cdr {134}{{x}}\@nil}\assert{{x}}
\let\test\@nnil\assert{\@nil}
\toks@={abc\test}\addto@hook\toks@{x\bar}
\expandafter\def\expandafter\test\expandafter{\the\toks@} \assert{abc\test x\bar}
\g@addto@macro\test{y\gee} \assert{abc\test x\bar y\gee}
\def\xx{456}
\def\test{123}\@cons\test{\xx78}\assert{123\@elt45678}
\@cons\test{\xx780}\assert{123\@elt45678}
% assert if defined
\assertdef\assert
\assertdef[\@@par is defined]\@@par
% asserts for fp values
\FPadd\test{1}{1}\assert[\FPadd\test{1}{1}==2.000000000000000000]{2.000000000000000000}
\FPadd\test{1}{1}\assert[\FPadd\test{1}{1}==2.00000000000000000]{2.000000000000000000}
\end{document}
人们可以更有创造力并创建额外的断言,例如\assertfalse
,\assertcat
用于类别代码检查等。据我了解,LaTeX3 团队做了很多测试;然而,将上述内容应用到学习环境中,我不太确定这样做是否可行或可取。
在教程中,你将主要测试如何掌握命令的使用。对于在线应用程序,我会选择Moodle带有用于考试和测验的内置结构的安装类型,但后来你选择了 Django:)
答案2
下面是我用来帮助编写的断言例程更新LaTeX lawtex 包。
\documentclass{article}
\usepackage{xstring} % IfEq, StrCompare
\usepackage{xcolor}
\newcounter{tst}
% \assert{test name}{string value1}{string value 2}- will test that
% the second argument matches the third argument and print in green if
% it passed or in red if it fails.
\long\def\assert#1#2#3{{% add a block to prevent namespace pollution
% Note that you cannot use the macro on macros with optional
% arguments because the macros won't expand properly in an edef.
% see https://tex.stackexchange.com/questions/21514/why-isnt-a-command-defined-by-newcommand-with-an-optional-argument-expandable
\edef\assertA{#2}\edef\assertB{#3}%
\def\name{\if\relax\detokenize{#1}\relax\detokenize{#2} = \detokenize{#3}\else #1\fi}%
\def\desc{\space Test:\,\stepcounter{tst}\thetst~(\name)\par}%
\comparestrict%
\IfEq{\assertA}{\assertB}{%
\textcolor{green}{Passed} \desc%
}{%
\ifcsname EnforceAssertions\endcsname%
\errmessage{Assertion \thetst (#1) failed. (#2) $\ne$ (#3)}%
\else%
\fi%
\textcolor{red}{Failed} \desc%
\par~~~~~~~~(\assertA)(\detokenize{#2}) $\ne$ \par~~~~~~~~(\assertB)(\detokenize{#3})\par%
First difference at position %
\comparestrict\StrCompare{\assertA}{\assertB}.\par%
}%
}}
\begin{document}
\def\hello#1{hello #1}
\assert{hello world}{\hello{world}}{hello world}
\assert{failing hello world}{\hello{world}}{hello cruel world}
\end{document}
如果使用定义的宏调用它\EnforceAssertions
,则断言错误将向日志文件打印错误消息。从命令行,我可以使用如下 bash 脚本进行测试:
#!/bin/bash
function dotest {
echo testing $1
pdflatex -halt-on-error "\def\EnforceAssertions{defined} \input{$1}" &> /dev/null && echo Test $1 passed || echo Test $1 FAILED.
}
export -f dotest
echo test.tex | parallel --timeout 1000% dotest
它的名字如下:
bash-4.4$ ./temptestall.sh
testing test.tex
Test test.tex FAILED.
这可能不是使用网络进行测试的最佳方式,但我将此答案放在这里,以便其他可能正在寻找测试框架来帮助编程 TeX/LaTeX 的人使用。