2

我想在一个模块上实现 100% 的覆盖率。我的问题是在我试图注入数据以测试我的异常处理的方法中有一个变量(称为数据)。这可以通过嘲笑来完成吗?如果不是,我该如何全面测试我的异常处理?

module CSV
  module Extractor
class ConversionError   < RuntimeError; end
class MalformedCSVError < RuntimeError; end
class GenericParseError < RuntimeError; end 
class DemoModeError     < RuntimeError; end

def self.open(path)
  data = `.\\csv2text.exe #{path} -f xml --xml_output_styles 2>&1`
  case data
  when /Error: Wrong input filename or path:/
    raise MalformedCSVError, "the CSV path with filename '#{path}' is malformed"
  when /Error: A valid password is required to open/
    raise ConversionError, "Wrong password: '#{path}'"
  when /CSVTron CSV2Text: This page is skipped when running in the demo mode./
    raise DemoModeError, "CSV2TEXT.exe in demo mode"
  when /Error:/
    raise GenericParseError, "Generic Error Catch while reading input file"
  else
    begin
      csvObj = CSV::Extractor::Document.new(data)
    rescue
      csvObj = nil
    end
    return csvObj
  end  
end
end
end

让我知道你的想法!谢谢

===================== 编辑========================

我已将我的方法修改为您建议的设计模式。这个方法-"open(path)" 负责捕获和引发错误,get_data(path) 只是返回数据,就是这样!但不幸的是,在 rspec 中,我得到“预计会引发异常,但没有引发任何异常”。我想也许我们也必须从你的存根中调用 open 方法?

这是我尝试做的,但仍然没有引发错误..

    it 'should catch wrong path mode' do
    obj = double(CSV::Extractor)
    obj.stub!(:get_data).and_return("Error: Wrong input filename or path:")
    obj.stub!(:open)
    expect {obj.open("some fake path")}.to raise_error CSV::Extractor::MalformedCSVError
    end
4

2 回答 2

1

提取将数据返回到单独方法的代码。然后,当您测试时,open您可以存根该方法以返回各种字符串,这些字符串将执行case语句的不同分支。设置大致是这样的:

def self.get_data(path)
  `.\\csv2text.exe #{path} -f xml --xml_output_styles 2>&1`
end

def self.open(path)
  data = get_data(path)
  ...

我假设您知道如何在 rspec 中存根方法,但总体思路是这样的:

foo = ...
foo.stub(:get_data).and_return("Error: Wrong input filename or path:")
expect { foo.get_data() }.to raise_error MalformedCSVError

另请参阅有关测试异常的 Rspec 文档。

于 2013-06-20T04:01:41.960 回答
0

测试模块的问题在于您设计代码的方式。考虑将提取器分成两个类(或模块,这取决于口味——我会选择类,因为它们更容易测试),其中一个会从外部系统调用中读取数据,第二个会期望这些数据作为参数传递。

通过这种方式,您可以轻松地模拟您当前在data变量中拥有的内容,因为这将简单地作为参数传递(无需考虑此处的实现细节!)。

为了更容易使用,您可以稍后提供一些包装器调用,这将创建两个对象并将一个作为参数传递给另一个。请注意,这种行为也可以很容易地测试。

于 2013-06-20T09:17:33.670 回答