在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" 
] 

功能beforeafter模仿你的安装/拆卸功能。函数withCodeAfter是一个帮助程序宏,它首先执行代码before,然后执行代码after,但作为结果返回before的结果。函数wrapTestwrapTest1说明了两种可能性:您可以定义单独的“之前”和“之后”函数,并将它们与代码夹在一起,也可以使用Block并定义“around”宏,有时可能更方便。测试将以任何方式工作。你也可以混合使用这些方法。在这两种情况下,样板代码的数量都很小 - 只需在每次测试前添加[email protected]行。

+0

好吧,我更新了我的问题有什么,我还以为你在谈论一位跛脚的例子。现在,我明白你在说什么了。谢谢 – mmorris 2012-01-03 22:29:35

+0

@mmorris感谢您的接受。您的更新确实是我在最初回答中的含义。我的更新只是为了展示如何用相对少的努力来减少样板代码的数量。 – 2012-01-03 22:43:51

+0

请参阅下面的答案。谢谢Mike – mmorris 2012-01-05 03:15:33

我无法格式化的评论,所以我这样做,作为一个答案正确...

好吧,我想我已经解剖的代码在你的答案,请让我知道如果我正确。


定义之前和“测试案例”后评估什么是评估。一个侧面说明,你正在定义fbefore,undefining fafter

(* 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中要评估的第一个表达式。评估的第一个表达式beforewithCodeAfter返回。

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"] 
+0

是的,你完全正确 - 这正是发生的事情。函数'withCodeAfter'只是一个方便的函数,它不是必须的 - 只是保存一个辅助变量的引入来保存'before'的结果。它实际上是一个宏,也许是我知道的有用宏的缩写。对不起,如果我的答案不是很清楚。 – 2012-01-05 10:08:54

+0

感谢您的理智检查! – mmorris 2012-01-05 13:14:39