在 MUnit 中寻找类似 JUnit 的 @Before / @After 的东西
我正在一个 .mt 文件中编写多个测试用例,这些测试用例共享通用的设置(和拆卸)过程。我希望看到像 JUnit 的 @Before
/ @After
这样的东西,但是 MUnit 包中没有任何东西让我想到可以实现这一点。老实说,MUnit 包文档比 Wolfram Workbench 的 MUnit 文档好一点,但它也远未完成。 有关查看MUnit 包。
因此,在我重新发明轮子之前,我想我应该检查一下我是否错过了 MUnit 中的某些内容,或者是否有人有一个运行良好的模式?
因此,根据 Leonid Shifrin 最初 的回答(当我将其放在一起时,他更新了他的答案),这就是我现在所在的位置......
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[];
I am writting a number of test cases in a single .mt file that share common setup (and teardown) procedure(s). I was hoping to see something like JUnit's @Before
/ @After
, but nothing from the MUnit package jumped out at me that that would accomplish this. In all honesty, the MUnit package documentation is a little better than the Wolfram Workbench's MUnit documentation, but it too is far from complete. Instructions on viewing the MUnit package.
So before I go reinventing the wheel, I thought I would check to see if I missed something in MUnit or if anyone has a pattern that works well?
So based on Leonid Shifrin initial answer (he updated his answer while I put this together) this is (was) where I am (was) at ...
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[];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
MUnit
文件是普通的包文件,它们是按顺序读取和执行的 - 或者至少这是我对它们的经验。您只需在测试之前和之后添加包含公共代码的行,它们将分别在所有测试之前和之后执行。如果您想为每个测试单独调用设置和拆卸过程,您可以在每个测试之前和之后添加相应的行(调用)。您可能会发现编写一个预处理器很方便,它将您的测试作为包加载(例如,通过使用
Import["Tests.tm","HeldExpressions"]
- 您的测试位于本例中为Tests.tm
),插入相应的行,然后再次保存文件。这将需要对所保存的代码进行一些流畅的操作,但可以相当快地掌握,并且如果您有很多测试,则非常方便。编辑
作为一种更轻量级的替代方案,您可以定义类似宏的快捷方式。以下是测试文件内容示例:
函数
before
和after
模仿您的设置/拆卸函数。函数withCodeAfter
是一个辅助宏,它首先执行代码before
,然后执行代码after
,但最终返回的结果之前
。函数wrapTest
和wrapTest1
说明了两种可能性:您可以定义单独的“before”和“after”函数并将代码与它们夹在中间,或者您可以使用块并定义“around”宏,有时这可能更方便。无论哪种方式,测试都会有效。您还可以混合使用这些方法。在这两种情况下,样板代码量都是最少的 - 只需在每次测试之前添加
wrapTest@
行即可。MUnit
files are normal package files, and they are read and executed sequentially - or at least this has been my experience with them. You can simply add lines with your common code before and after your tests, and they will be executed before and after all the tests respectively.If you want to invoke your setup and teardown procedures individually for each test, you can add the corresponding lines (calls) just before and just after each test. You may find it convenient then to write a preprocessor, which would load your tests as a package (for example, by using
Import["Tests.tm","HeldExpressions"]
- where your tests are inTests.tm
in this example), and inserting the corresponding lines and then saving a file again. This will require some fluency with manipulations with held code, but can be picked up reasonably quickly, and is very convenient if you have many tests.EDIT
As a more light-weight alternative, you can define macro-like short-cuts. Here is an example test file contents:
The functions
before
andafter
imitate your setup / teardown functions. The functionwithCodeAfter
is a helper macro which executes codebefore
first, then executes codeafter
, but as a result returns the result ofbefore
. The functionswrapTest
andwrapTest1
illustrate two possibilities: you can either define separate "before" and "after" functions and sandwich your code with them, or you can useBlock
and define the "around" macro, which may be sometimes more convenient. Tests will work either way. You can also mix these approaches. In both cases, the amount of boilerplate code is minimal - just addwrapTest@
line before each test.我无法在评论中获得正确的格式,因此我将其作为答案...
好吧,我想我已经在您的答案中剖析了代码,请告诉我我是否正确。
定义评估“测试用例”之前和之后评估的内容。附注,您在
before
中定义f
,在after
中取消定义f
。定义函数
withCodeAfter
。它需要两个表达式,第一个表达式before
在传入时进行求值。第二个表达式after
传入时未求值,并且是要在其中求值的第一个表达式withCodeAfter
。计算的第一个表达式before
由withCodeAfter
返回。定义函数
wrapTest
。它需要一个表达式,code
,该表达式在未计算的情况下传入。该表达式code
是复合表达式before[];code
的第二个表达式,该复合表达式作为第一个表达式before
传递,到withCodeAfter
。复合表达式before[];code
在传递到withCodeAfter
时进行计算。求值表达式的值code
由withCodeAfter
在after
求值之后返回。withCodeAfter
返回的值由wrapTest
返回。与调用
wrapTest[Test[f[2], 8, TestID -> > 是一样的“我的测试1”]]
I can't get the formatting correct in the comment so I am doing this as an answer...
Okay I think I have the dissected the code in your answer, please let me know if I am correct.
Defines what is evaluated before and after the "test case" is evaluated. A side note, you are defining
f
inbefore
, undefiningf
inafter
.Defines the function
withCodeAfter
. It takes two expressions, the first expression,before
, is evaluated when passed in. The second expression,after
, is passed in unevaluated and is the first expression to be evaluated withinwithCodeAfter
. The evaluated first expression,before
, is returned bywithCodeAfter
.Defines the function
wrapTest
. It takes one expression,code
, that is passed in unevaluated. That expression,code
, is the second expression of a compound expression,before[];code
, that is passed as the first expression,before
, towithCodeAfter
. The compound expression,before[];code
, is evaluated when passed intowithCodeAfter
. The value of the evaluated expression,code
, is returned bywithCodeAfter
followingafter
being evaluated. The value returned bywithCodeAfter
is returned bywrapTest
.Is the same thing as calling
wrapTest[Test[f[2], 8, TestID -> "MyTest1"]]