【问题标题】:How to spec methods that exit or abort如何指定退出或中止的方法
【发布时间】:2014-08-17 11:32:57
【问题描述】:

我有一个从 CLI 触发的方法,该方法具有一些明确退出或中止的逻辑路径。我发现在为此方法编写规范时,RSpec 将其标记为失败,因为出口是异常。这是一个简单的例子:

def cli_method
  if condition
    puts "Everything's okay!"
  else
    puts "GTFO!"
    exit
  end
end

我可以使用 should raise_error(SystemExit) 将规范包装在 lambda 中,但这会忽略块内发生的任何断言。需要明确的是:我不是在测试出口本身,而是在它之前发生的逻辑。我该如何指定这种方法?

【问题讨论】:

标签: ruby rspec


【解决方案1】:

只需将您的断言放在 lambda 之外,例如:

class Foo
  attr_accessor :result

  def logic_and_exit
    @result = :bad_logic
    exit
  end
end

describe 'Foo#logic_and_exit' do
  before(:each) do
    @foo = Foo.new
  end

  it "should set @foo" do
    lambda { @foo.logic_and_exit; exit }.should raise_error SystemExit
    @foo.result.should == :logics
  end
end

当我运行 rspec 时,它正确地告诉我:

expected: :logics
     got: :bad_logic (using ==)

在任何情况下这对您不起作用?

编辑:我在 lambda 中添加了一个“退出”调用来处理 logic_and_exit 不退出的情况。

EDIT2:更好的是,在你的测试中这样做:

begin
  @foo.logic_and_exit
rescue SystemExit
end
@foo.result.should == :logics

【讨论】:

    【解决方案2】:

    涵盖 Rspec 3 的期望语法的新答案。

    测试输出

    只是为了测试您真正想要的(即您不是在测试异常或值响应)输出到 STDOUT 的内容。

    condition 为假时

    it "has a false condition" do
      # NOTE: Set up your condition's parameters to make it false
      expect {
        begin cli_method
        rescue SystemExit
        end
      }.to output("GTFO").to_stdout # or .to_stderr
    end
    

    condition 为真时

    it "has a true condition" do
      # NOTE: Set up your condition's parameters to make it true
      expect {
        begin cli_method
        rescue SystemExit
        end
      }.to output("Everything's okay!").to_stdout
    end
    

    请注意,output("String").to_... 可以接受 Regex,例如。

    output(/^Everything's okay!$/).to_stdout
    

    它也可以从stderr例如捕获。

    output("GTFO").to_stderr
    

    (对于 OP 的示例,这将是一个更好的发送位置。)

    测试出口

    您可以单独测试错误条件也引发SystemExit

    it "exits when condition is false" do
      # NOTE: Set up your condition's parameters to make it false
      expect{cli_method}.to raise_error SystemExit
    end
    
    it "doesn't exit when condition is true" do
      # NOTE: Set up your condition's parameters to make it true
      expect{cli_method}.not_to raise_error SystemExit
    end
    

    【讨论】:

      【解决方案3】:

      我可以使用 should raise_error(SystemExit) 将规范包装在 lambda 中, 但这忽略了块内发生的任何断言。

      我看不出在 lambda 内部或外部进行测试有什么不同。无论哪种情况,失败消息都有些神秘:

      def cli_method(condition)
        if condition
          puts "OK"
        else
          puts "GTFO"
          exit
        end
      end
      
      describe "cli_method" do
        context "outside lambda" do
          # passing
          it "writes to STDOUT when condition is false" do
            STDOUT.should_receive(:puts).with("GTFO")
            lambda {
              cli_method(false)
            }.should raise_error(SystemExit)
          end
      
          # failing
          it "does not write to STDOUT when condition is false" do
            STDOUT.should_not_receive(:puts).with("GTFO")
            lambda {
              cli_method(false)
            }.should raise_error(SystemExit)
          end
        end
        context "inside lambda" do
          # passing
          it "writes to STDOUT when condition is false" do
            lambda {
              STDOUT.should_receive(:puts).with("GTFO")
              cli_method(false)
            }.should raise_error(SystemExit)
          end
      
          # failing
          it "does not write to STDOUT when condition is false" do
            lambda {
              STDOUT.should_not_receive(:puts).with("GTFO")
              cli_method(false)
            }.should raise_error(SystemExit)
          end
        end
      end
      
       # output
      .F.F
      
      Failures:
      
        1) cli_method outside lambda does not write to STDOUT when condition is false
           Failure/Error: lambda {
             expected SystemExit, got #<RSpec::Mocks::MockExpectationError: (#<IO:0xb28cd8>).puts("GTFO")
                 expected: 0 times
                 received: 1 time>
           # ./gtfo_spec.rb:23:in `block (3 levels) in <top (required)>'
      
        2) cli_method inside lambda does not write to STDOUT when condition is false
           Failure/Error: lambda {
             expected SystemExit, got #<RSpec::Mocks::MockExpectationError: (#<IO:0xb28cd8>).puts("GTFO")
                 expected: 0 times
                 received: 1 time>
           # ./gtfo_spec.rb:39:in `block (3 levels) in <top (required)>'
      

      【讨论】:

        猜你喜欢
        • 2011-12-17
        • 2011-02-18
        • 1970-01-01
        • 2014-10-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多