在MUnit寻找像JUnit的@Before/@After之类的东西
我在一个共享通用设置(和拆卸)过程的单个.mt文件中写入了大量测试用例。我希望看到像JUnit的@Before
/@After
这样的东西,但是没有任何东西从MUnit包中跳出来,那样就可以实现这一点。老实说,MUnit软件包文档比Wolfram Workbench的MUnit文档稍好一些,但它也远没有完成。因此,在我开始重新发明*之前,我想我会检查是否在MUnit中遗漏了某些东西,或者如果有人有一种运行良好的模式?在MUnit寻找像JUnit的@Before/@After之类的东西
因此,基于列昂尼德·希夫林初始答案(他更新了自己的答案,而我把这个在一起),这是(是)我所在的地方(是)在...
TestPlus.mt
(* Mathematica Test File *)
(* x is a global value *)
x=0;
SetUp[] := Module[{}, x=1;];
TearDown[] := Module[{}, x=0;];
(* test SetUp[] *)
SetUp[];
Test[x, 1, TestID->"SetUp-20120103-F2U9V6"]
(* test TearDown[] *)
TearDown[];
Test[x, 0, TestID->"TearDown-20120103-O4R6M7"]
(* test plus --contrived tests-- *)
SetUp[];
Test[x+0, 1, TestID->"Plus-20120103-S5D9X6"]
TearDown[];
SetUp[];
Test[x+1, 2, TestID->"Plus-20120103-D7Q3E0"]
TearDown[];
SetUp[];
Test[x+2, 3, TestID->"Plus-20120103-F0S4P9"]
TearDown[];
MUnit
文件是正常的包文件,并将它们读取和顺序执行的 - 或者至少这是我与他们的经验。您可以简单地在测试前后使用通用代码添加行,并且它们将分别在所有测试之前和之后执行。
如果您想针对每个测试单独调用设置和拆卸过程,可以在每次测试之前和之后添加相应的行(调用)。你可能会发现编写一个预处理器会很方便,它将把你的测试作为一个包加载(例如,通过使用Import["Tests.tm","HeldExpressions"]
--在这个例子中你的测试在Tests.tm
中),然后插入相应的行并再次保存文件。这需要一定的流利度来操作保存的代码,但可以快速合理地选择,如果您有很多测试,则非常方便。
EDIT
作为更轻质的替代,可以定义宏状捷径。下面是一个例子测试文件内容:
(* Mathematica Test File *)
before[]:= (Print["Before Test: ",f[2]];f[x_]:=x^3);
after[] := (ClearAll[f];Print["After Test: ",f[2]]);
SetAttributes[withCodeAfter,HoldRest];
withCodeAfter[before_,after_]:=(after;before)
SetAttributes[{wrapTest,wrapTest1},HoldAll]
wrapTest[code_]:= withCodeAfter[before[];code,after[]]
wrapTest1[code_]:=Block[{f},f[x_]:=x^3;code];
[email protected]
Test[f[2],
8,
TestID -> "MyTest1"
]
[email protected]
Test[f[2],
8,
TestID -> "MyTest2"
]
功能before
和after
模仿你的安装/拆卸功能。函数withCodeAfter
是一个帮助程序宏,它首先执行代码before
,然后执行代码after
,但作为结果返回before
的结果。函数wrapTest
和wrapTest1
说明了两种可能性:您可以定义单独的“之前”和“之后”函数,并将它们与代码夹在一起,也可以使用Block
并定义“around”宏,有时可能更方便。测试将以任何方式工作。你也可以混合使用这些方法。在这两种情况下,样板代码的数量都很小 - 只需在每次测试前添加[email protected]
行。
我无法格式化的评论,所以我这样做,作为一个答案正确...
好吧,我想我已经解剖的代码在你的答案,请让我知道如果我正确。
定义之前和“测试案例”后评估什么是评估。一个侧面说明,你正在定义f
在before
,undefining f
在after
。
(* Mathematica Test File *)
before[]:= (Print["Before Test: ",f[2]];f[x_]:=x^3);
after[] := (ClearAll[f];Print["After Test: ",f[2]]);
定义功能withCodeAfter
。它需要两个表达式,第一个表达式before
在传入时进行评估。第二个表达式after
未被评估,并且是withCodeAfter
中要评估的第一个表达式。评估的第一个表达式before
由withCodeAfter
返回。
SetAttributes[withCodeAfter,HoldRest];
withCodeAfter[before_,after_]:=(after;before)
定义功能wrapTest
。它需要一个表达式,code
,传入未评估。该表达式code
是化合物表达式before[];code
的第二表达式,其作为第一表达式before
传递至withCodeAfter
。在传递到withCodeAfter
时评估化合物表达式before[];code
。评估的表达式code
的值由withCodeAfter
返回,其后after
被评估。 withCodeAfter
返回的值由wrapTest
返回。
SetAttributes[{wrapTest},HoldAll]
wrapTest[code_]:= withCodeAfter[before[];code,after[]]
是一回事调用wrapTest[Test[f[2], 8, TestID -> "MyTest1"]]
[email protected]
Test[f[2], 8, TestID -> "MyTest1"]
是的,你完全正确 - 这正是发生的事情。函数'withCodeAfter'只是一个方便的函数,它不是必须的 - 只是保存一个辅助变量的引入来保存'before'的结果。它实际上是一个宏,也许是我知道的有用宏的缩写。对不起,如果我的答案不是很清楚。 – 2012-01-05 10:08:54
感谢您的理智检查! – mmorris 2012-01-05 13:14:39
好吧,我更新了我的问题有什么,我还以为你在谈论一位跛脚的例子。现在,我明白你在说什么了。谢谢 – mmorris 2012-01-03 22:29:35
@mmorris感谢您的接受。您的更新确实是我在最初回答中的含义。我的更新只是为了展示如何用相对少的努力来减少样板代码的数量。 – 2012-01-03 22:43:51
请参阅下面的答案。谢谢Mike – mmorris 2012-01-05 03:15:33