在 Ruby 的 Test::Unit::TestCase 中,如何重写初始化方法?
我正在与 Test::Unit 作斗争。 当我想到单元测试时,我想到每个文件一个简单的测试。 但在 Ruby 的框架中,我必须改为这样写:
class MyTest < Test::Unit::TestCase
def setup
end
def test_1
end
def test_1
end
end
但是每次调用 test_* 方法时都会运行安装和拆卸。 这正是我不想要的。 相反,我想要一个为整个班级运行一次的设置方法。 但我似乎无法在不破坏 TestCase 初始化的情况下编写自己的初始化()。
那可能吗? 还是我让这件事变得极其复杂?
I'm struggling with Test::Unit. When I think of unit tests, I think of one simple test per file. But in Ruby's framework, I must instead write:
class MyTest < Test::Unit::TestCase
def setup
end
def test_1
end
def test_1
end
end
But setup and teardown run for every invocation of a test_* method. This is exactly what I don't want. Rather, I want a setup method that runs just once for the whole class. But I can't seem to write my own initialize() without breaking TestCase's initialize.
Is that possible? Or am I making this hopelessly complicated?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(10)
正如 Hal Fulton 的书《The Ruby Way》中提到的。
他重写了 Test::Unit 的 self.suite 方法,该方法允许类中的测试用例作为套件运行。
这是一个例子:
As mentioned in Hal Fulton's book "The Ruby Way".
He overrides the self.suite method of Test::Unit which allows the test cases in a class to run as a suite.
Here is an example:
最终,测试单元已实现此功能! 哇!
如果您使用的是 v 2.5.2 或更高版本,您可以只使用它:
这将在您开始测试时运行一次。 除了在每个测试(设置)之前运行的回调之外,还有在每个测试用例(启动)开始时运行的回调。
http://test-unit.rubyforge.org /test-unit/en/Test/Unit.html#at_start-class_method
FINALLY, test-unit has this implemented! Woot!
If you are using v 2.5.2 or later, you can just use this:
This will run once when you start your tests off. There are also callbacks which run at the beginning of each test case (startup), in addition to the ones that run before every test (setup).
http://test-unit.rubyforge.org/test-unit/en/Test/Unit.html#at_start-class_method
这就是它应该如何工作的!
每个测试都应该与其他测试完全隔离,因此每个测试用例的
setup
和tear_down
方法都会执行一次。 然而,在某些情况下,您可能希望对执行流程有更多控制。 然后您可以将测试用例分组到套件中。在您的情况下,您可以编写如下内容:
TestDecorator
定义了一个特殊的套件,它提供了setup
和tear_down
方法,这些方法之前只运行一次并在运行它包含的一组测试用例之后。这样做的缺点是您需要告诉 Test::Unit 如何在单元中运行测试。 如果您的单元包含许多测试用例,并且您只需要其中一个测试用例的装饰器,那么您将需要这样的东西:
Test::Unit 文档 文档提供了有关套件如何工作的良好解释。
That's how it's supposed to work!
Each test should be completely isolated from the rest, so the
setup
andtear_down
methods are executed once for every test-case. There are cases, however, when you might want more control over the execution flow. Then you can group the test-cases in suites.In your case you could write something like the following:
The
TestDecorator
defines a special suite which provides asetup
andtear_down
method which run only once before and after the running of the set of test-cases it contains.The drawback of this is that you need to tell Test::Unit how to run the tests in the unit. In the event your unit contains many test-cases and you need a decorator for only one of them you'll need something like this:
The Test::Unit documentation documentation provides a good explanation on how suites work.
好吧,我以一种非常丑陋和可怕的方式完成了基本相同的方式,但速度更快。 :) 一旦我意识到测试是按字母顺序运行的:
它并不漂亮,但它有效:)
Well, I accomplished basically the same way in a really ugly and horrible fashion, but it was quicker. :) Once I realized that the tests are run alphabetically:
It aint pretty, but it works :)
为了解决这个问题,我使用了设置构造,仅遵循一种测试方法。 这一测试方法正在调用所有其他测试。
例如
To solve this problem I used the setup construct, with only one test method followed. This one testmethod is calling all other tests.
For instance
我知道这是一篇相当老的帖子,但我遇到了这个问题(并且已经使用 Tes/unit 编写了类)并且已经使用另一种方法进行了回答,所以如果它可以提供帮助......
如果您只需要相当于启动功能,您可以使用类变量:
I know this is quite an old post, but I had the issue (and had already written classes using Tes/unit) and ave answered using another method, so if it can help...
If you only need the equivalent of the startup function, you can use the class variables:
我遇到了这个确切的问题,并创建了
Test::Unit::TestCase
的子类来准确执行您所描述的操作。这就是我的想法。 它提供了自己的
setup
和teardown
方法,用于计算类中以“test”开头的方法的数量。 第一次调用setup
时,它会调用global_setup
,最后一次调用teardown
时,它会调用global_teardown
创建您的测试像这样的情况:
这种情况的错误是您无法提供自己的每个测试
setup
和teardown
方法,除非您使用setup :method_name 类方法(仅在 Rails 2.X 中可用?),如果您有一个测试套件或仅运行其中一个测试方法的东西,则不会调用
global_teardown
因为它假设最终将运行所有测试方法。I came across this exact problem and created a subclass of
Test::Unit::TestCase
for doing exactly what you describe.Here's what I came up with. It provides it's own
setup
andteardown
methods that count the number of methods in the class that begin with 'test'. On the first call tosetup
it callsglobal_setup
and on the last call toteardown
it callsglobal_teardown
Create your test cases like this:
The fault in this is that you can't provide your own per-test
setup
andteardown
methods unless you use thesetup :method_name
class method (only available in Rails 2.X?) and if you have a test suite or something that only runs one of the test methods, then theglobal_teardown
won't be called because it assumes that all the test methods will be run eventually.使用 @romulo-a-ceccon 描述的 TestSuite 来为每个测试套件进行特殊准备。
但是我认为这里应该提到单元测试是完全隔离运行的。 因此,执行流程是设置-测试-拆卸,这应该保证每个测试的运行不受其他测试所做的任何事情的干扰。
Use the TestSuite as @romulo-a-ceccon described for special preparations for each test suite.
However I think it should be mentioned here that Unit tests are ment to run in total isolation. Thus the execution flow is setup-test-teardown which should guarantee that each test run undisturbed by anything the other tests did.
我创建了一个名为 SetupOnce 的 mixin。 这是一个使用它的示例。
这是实际的代码; 请注意,它需要脚注中第一个链接提供的另一个模块。
脚注:
http://redcorundum.blogspot.com /2006/06/mixing-in-class-methods.html
http://infovore.org /archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
I created a mixin called SetupOnce. Here's an example of using it.
And here is the actual code; notice it requires another module available from the first link in the footnotes.
Footnotes:
http://redcorundum.blogspot.com/2006/06/mixing-in-class-methods.html
http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
为上面 @orion-edwards 的 RSpec 答案+1。 我会对他的答案发表评论,但我还没有足够的声誉来对答案发表评论。
我经常使用 test/unit 和 RSpec,我不得不说...每个人发布的代码都缺少
before( 的一个非常 重要功能:all)
即:@instance 变量支持。在 RSpec 中,您可以执行以下操作:
#startup
和#shutdown
的实现首先侧重于确保这些方法在整个TestCase< 中仅被调用一次/code> 类,但是这些方法中使用的任何实例变量都会丢失!
RSpec 在它自己的 Object 实例中运行它的
before(:all)
,并且在每个测试运行之前复制所有局部变量。要访问在全局
#startup
方法期间创建的任何变量,您需要:#startup
创建的所有实例变量,就像 RSpec 定义#startup
中的变量放入您可以从测试方法访问的范围内,例如@@class_variables
或创建类级 attr_accessors,提供对您在def self.startup
内部创建的@instance_variables
的访问,只需我的 0.02 美元!
+1 for the RSpec answer above by @orion-edwards. I would have commented on his answer, but I don't have enough reputation yet to comment on answers.
I use test/unit and RSpec a lot and I have to say ... the code that everyone has been posting is missing a very important feature of
before(:all)
which is: @instance variable support.In RSpec, you can do:
The implementations of
#startup
and#shutdown
above all focus on making sure that these methods only get called once for the entireTestCase
class, but any instance variables used in these methods would be lost!RSpec runs its
before(:all)
in its own instance of Object and all of the local variables are copied before each test is run.To access any variables that are created during a global
#startup
method, you would need to either:#startup
, like RSpec does#startup
into a scope that you can access from your test methods, eg.@@class_variables
or create class-level attr_accessors that provide access to the@instance_variables
that you create inside ofdef self.startup
Just my $0.02!