2

在我的代码中,我有类似于以下人为示例的代码。

class Excel
  def self.do_tasks
    with_excel do |excel|
      delete_old_exports
      export_images(excel)
      export_documents(excel)
    end
  end

  def with_excel
    excel = WIN32OLE.connect('Excel.Application')
    begin
      yield excel
    ensure
      excel.close()
    end
  end
end

现在,我想为“do_tasks”方法编写一个测试,在其中设置方法调用的期望值,看看这些期望值是否得到满足。

我尝试了以下方法(使用 shoulda-context 和 test-unit)。但是,最后三个模拟的预期失败(模拟没有被调用)。

class ExcelTest < ActiveSupport::TestCase  
  should "call the expected methods" do  
    mock.proxy(Excel).with_excel
    mock(Excel).delete_old_exports
    mock(Excel).export_images.with_any_args
    mock(Excel).export_documents.with_any_args

    Excel.do_tasks
  end
end

任何有关如何测试此类代码的指针将不胜感激!

4

1 回答 1

1

一个较老的问题,但我刚刚用 rr 对一些类似的代码进行了一些工作,并认为我会给出一个答案。

以下测试将按照您的要求进行(使用 RR 和 TestUnit):

describe Excel do
  describe '.do_tasks' do
    let(:excel_ole) { mock!.close.subject }

    before do
      stub(WIN32OLE).connect('Excel.Application') { excel_ole }
      mock(Excel).delete_old_exports
      mock(Excel).export_images(excel_ole)
      mock(Excel).export_documents(excel_ole)
    end

    it 'calls the expected methods' do
      Excel.do_tasks
      assert_received(Excel) { |subject| subject.delete_old_exports }
    end
  end
end

它使用 RR 的“间谍”双打 - 见https://github.com/rr/rr#sies

但是,对于您提供的示例代码,您要测试的方法位于块内这一事实是一个实现细节,不应隐式测试(这可能导致脆弱的测试)。上面的测试显示了这一点,with_excel 方法没有被模拟(顺便说一下,这应该定义为 self.with_excel 以使代码工作)。可以重构实现,以便 WIN32OLE 初始化和拆卸在 .do_tasks 方法中内联发生,并且测试仍然可以通过。

另一方面,这可能是人为示例的副作用,但总的来说,测试非公共方法是个坏主意。方法 delete_old_exports、export_images 和 export_documents 看起来可能应该对合作者进行分解。

于 2013-04-17T09:04:58.110 回答