检测 ruby​​ 测试方法的覆盖

发布于 2024-07-13 17:58:43 字数 524 浏览 8 评论 0原文

这样的测试类,

class MyTest < Test::Unit::TestCase 
  def setup 
  end

  def test_1 
    flunk
  end

  def test_1 
    assert true
  end
end

如果您编写像第一个 test_1 则会被忽略。 尽管这看起来像是一个愚蠢的错误,但复制和粘贴编程时可能会发生这种情况。 除了运行

grep test test_me.rb | wc

并比较测试单元所说的已运行的测试数量,或使用 rcov 或 heckle,或使用 -w 运行之外,您如何检测此类问题?

另外,有什么方法可以指定测试方法不应被覆盖吗?

编辑:正在测试的方法有一个大约有 6 个可能值的参数,测试人员想要测试每个场景。 这就是使用复制和粘贴编程的原因。 对于这种情况,我可以设想的唯一替代方案是参数和期望值的六元素数组。

If you write a test class like

class MyTest < Test::Unit::TestCase 
  def setup 
  end

  def test_1 
    flunk
  end

  def test_1 
    assert true
  end
end

the first test_1 is ignored. Although it looks like a stupid mistake, it can happen with copy and paste programming. Apart from running

grep test test_me.rb | wc

and comparing that with how many tests test unit says has run, or using rcov or heckle, or running with -w, how can you detect such issues?

Also, is there any way of specifying that test methods shouldn't be overwritten?

Edit: The method being tested had a parameter with 6 or so possible values, and the tester wanted to test each scenario. This was why copy and paste programming was used. The only alternative I can envisage for such a scenario is a a six-element array of parameters and expected values.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

枉心 2024-07-20 17:58:43

您可以利用 Ruby 的 method_added,只要将方法添加到类中,它就会被调用。 您应该能够将某些内容添加到您包含的模块中,但这里有一个在测试类中执行此操作的简单示例。

class MyTest < Test::Unit::TestCase

  @@my_tests = []

  def self.method_added(sym)
    raise "#{sym} already defined!" if @@my_tests.include? sym
    @my_tests << sym
  end

  def test_foo_1
  end

  def test_foo_2
  end

  def test_foo_1
  end
end

You can take advantage of Ruby's method_added that gets called anytime a method is added to a class. You should be able to can something into a module that you include, but here is a simple example of doing it inside your test class.

class MyTest < Test::Unit::TestCase

  @@my_tests = []

  def self.method_added(sym)
    raise "#{sym} already defined!" if @@my_tests.include? sym
    @my_tests << sym
  end

  def test_foo_1
  end

  def test_foo_2
  end

  def test_foo_1
  end
end
酒绊 2024-07-20 17:58:43

编辑:正在测试的方法有一个
参数有6个左右可能
值,并且测试人员想要测试
每个场景。 这就是为什么复制和
使用粘贴编程。

在这种情况下,我这样做:

def test_foo
  test_cases = [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ]

  for test_case in test_cases
    do_the_test(test_case)
  end
end

def do_the_test(test_case)
  # test code here
end

这完全避免了复制和粘贴,正如已经说过的那样,这是不好的

唯一的
我可以设想这样的替代方案
场景是一个六元素数组
参数和期望值。

确切地!

Edit: The method being tested had a
parameter with 6 or so possible
values, and the tester wanted to test
each scenario. This was why copy and
paste programming was used.

In those circumstances I do this:

def test_foo
  test_cases = [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ]

  for test_case in test_cases
    do_the_test(test_case)
  end
end

def do_the_test(test_case)
  # test code here
end

This completely avoids copy and paste, which as has been said, is bad

The only
alternative I can envisage for such a
scenario is a a six-element array of
parameters and expected values.

Exactly!

丿*梦醉红颜 2024-07-20 17:58:43

关于 HermanD 的回答,因为这是 Ruby!,您也可以直接在类中执行此操作以创建独特的测试方法:

class MyObjectTest < Test::Unit::TestCase
  [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ].each do |test_case|
    define_method :"test_using_#{test_case[:param]}_should_return_#{params[:expected].underscore}" do
      assert_equal test_case[:expected], MyObject.new.do_something_with(test_case[:param])
    end
  end
end

使用 Rspec 的(或 Shoulda 的)类似句子的语言感觉更自然:

describe MyObject do
   [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ].each do |test_case|
    it "should return #{test_case[:expected]} when using #{test_case[:param]}" do
      MyObject.new.do_something_with(test_case[:param]).should == test_case[:expected]
    end
  end
end

Regarding HermanD's answer, since this is Ruby!, you can also do this directly in the class to create unique test methods:

class MyObjectTest < Test::Unit::TestCase
  [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ].each do |test_case|
    define_method :"test_using_#{test_case[:param]}_should_return_#{params[:expected].underscore}" do
      assert_equal test_case[:expected], MyObject.new.do_something_with(test_case[:param])
    end
  end
end

It feels even more natural using Rspec's (or Shoulda's) sentence like language:

describe MyObject do
   [
   {:param => 1, :expected => 'whatever is expected'},
   {:param => 2, :expected => 'whatever is expected'},
   {:param => 3, :expected => 'whatever is expected'},
   {:param => 4, :expected => 'whatever is expected'},
   {:param => 5, :expected => 'whatever is expected'},
   {:param => 6, :expected => 'whatever is expected'}
  ].each do |test_case|
    it "should return #{test_case[:expected]} when using #{test_case[:param]}" do
      MyObject.new.do_something_with(test_case[:param]).should == test_case[:expected]
    end
  end
end
用心笑 2024-07-20 17:58:43

如果您为测试提供正确的描述性名称,这真的是一个问题吗? 以下是我最近的项目中一些测试方法名称的示例:

test_should_not_do_html_escaping_for_administrators
test_should_not_be_able_to_create_project_with_company_user_doesnt_own
test_should_be_able_to_edit_own_projects
test_should_not_be_able_to_edit_others_projects

如果您的测试名称足够短,您可以轻松地覆盖或复制它们,那么您可能没有足够描述每个测试名称中实际测试的内容。

Is this really a problem if you're giving your tests proper descriptive names? Here's an example of some test method names from my most recent project:

test_should_not_do_html_escaping_for_administrators
test_should_not_be_able_to_create_project_with_company_user_doesnt_own
test_should_be_able_to_edit_own_projects
test_should_not_be_able_to_edit_others_projects

If your test names are short enough that you can easily overwrite or duplicate them, you're probably not being descriptive enough as to what you're actually testing in each one.

仄言 2024-07-20 17:58:43

避免复制粘贴编程。 如果需要,请重新绑定快捷键。

Avoid Copy-Paste programming. Rebind the key shortcuts if you have to.

寂寞陪衬 2024-07-20 17:58:43

The gem version of test-unit has the ability to detect test redefining as of 2.0.7.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文