如何指定退出或中止的方法

发布于 2024-11-29 06:13:48 字数 356 浏览 0 评论 0原文

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

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

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

I have a method being triggered from a CLI that has some logical paths which explicitly exit or abort. I have found that when writing specs for this method, RSpec marks it as failing because the exits are exceptions. Here's a a bare bones example:

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

I can wrap the spec in a lambda with should raise_error(SystemExit), but that disregards any assertions that happen inside the block. To be clear: I'm not testing the exit itself, but the logic that happens before it. How might I go about speccing this type of method?

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

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

发布评论

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

评论(3

一个人的旅程 2024-12-06 06:13:48

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

测试输出

只是为了测试您实际想要的内容(即您没有测试异常或值响应)输出到 STDOUT 的内容。

condition 为 false

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 为 true 时

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

New answer to cover Rspec 3's expect syntax.

Testing the output

Just to test what you actually want (ie. you're not testing the exception, or a value response,) what has been output to STDOUT.

When condition is false

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

When condition is true

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

Note that output("String").to_... can accept a Regex eg.

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

It can also capture from stderr eg.

output("GTFO").to_stderr

(Which would be a better place to send it, for the OP's example.)

Testing the Exit

You can separately test that the false condition also raises 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
帅气称霸 2024-12-06 06:13:48

只需将您的断言放在 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 不退出的情况。

编辑2:更好的是,只需在测试中执行以下操作:

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

Simply put your assertions outside of the lambda, for example:

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

When I run rspec, it correctly tells me:

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

Is there any case where this wouldn't work for you?

EDIT: I added an 'exit' call inside the lambda to hande the case where logic_and_exit doesn't exit.

EDIT2: Even better, just do this in your test:

begin
  @foo.logic_and_exit
rescue SystemExit
end
@foo.result.should == :logics
无声无音无过去 2024-12-06 06:13:48

我可以使用 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)>'

I can wrap the spec in a lambda with should raise_error(SystemExit),
but that disregards any assertions that happen inside the block.

I don't see a difference putting tests inside or outside the lambda. In either case, the failure message is a bit cryptic:

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