如何测试此方法RSPEC

发布于 2025-02-13 06:46:13 字数 1252 浏览 0 评论 0 原文

我有这个方法 - select_option 态

在此处输入图像描述

问题,我如何测试和参加绿灯simpelcov。

allow(adapter).to receive(:gets).and_return('my_guess')
except(adapter).to receive(:adapter_my_guess)

但这没有工作 错误:

expected: 1 time with any arguments
received: 2 times

因为我的包装器一直都在调用select_option似乎是递归

def adapter_my_guess(guess)
  @game.instance_variable_set(:@secret_code, %w[1 2 3 4])
  if @game.attempts.positive?
     puts show_guess_result(@game.my_guess(guess))
  else
     puts I18n.t(:lose_game, secret_code: @game.instance_variable_get(:@secret_code))
  end
end

def wrapper(method_for_wrap)
  puts method_for_wrap
  @game.win == false ? choose_option : Finishe.new(@game, @statistics).finishe
end

def choose_option
  option = input(I18n.t(:start_game_options, option1: OPTION_1, option2: OPTION_2, exit: EXIT))
  case option
  when OPTION_1 then wrapper(adapter_my_guess(input(I18n.t(:puts_guess, exit: OR_EXIT))))
  when OPTION_2 then wrapper(adapter_give_hints)
  else
    raise(StandardError, WRONG_OPTION)
  end
rescue StandardError => e
  puts e
  choose_option

结束

I have this method - choose_option
enter image description here

and this help methods
enter image description here

Question, how can i test and take green light simpelcov.

allow(adapter).to receive(:gets).and_return('my_guess')
except(adapter).to receive(:adapter_my_guess)

But this don' work
Error:

expected: 1 time with any arguments
received: 2 times

Because my wrapper all time call choose_option seems like recursion

def adapter_my_guess(guess)
  @game.instance_variable_set(:@secret_code, %w[1 2 3 4])
  if @game.attempts.positive?
     puts show_guess_result(@game.my_guess(guess))
  else
     puts I18n.t(:lose_game, secret_code: @game.instance_variable_get(:@secret_code))
  end
end

def wrapper(method_for_wrap)
  puts method_for_wrap
  @game.win == false ? choose_option : Finishe.new(@game, @statistics).finishe
end

def choose_option
  option = input(I18n.t(:start_game_options, option1: OPTION_1, option2: OPTION_2, exit: EXIT))
  case option
  when OPTION_1 then wrapper(adapter_my_guess(input(I18n.t(:puts_guess, exit: OR_EXIT))))
  when OPTION_2 then wrapper(adapter_give_hints)
  else
    raise(StandardError, WRONG_OPTION)
  end
rescue StandardError => e
  puts e
  choose_option

end

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

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

发布评论

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

评论(1

梦年海沫深 2025-02-20 06:46:13

evef(apapter).to接收(:adapter_my_guess) ADAPTER 将接收一个和只有一个呼叫 adapter_my_guess 。它收到了两个。

如果是正确的,请 at_least(1).Time ,期待更多电话

如果这是不正确的,我们需要更多地了解您的代码和测试。


一些注释...

不使用 instance_variable_get instance_variable_set 在生产代码中。抓住另一个对象的内部变量将代码纠缠不清,并使对象很难而不会产生不可预见的后果。 make secret_code 适当的 consector方法

select_option 做三件事。它获取选项,它可以解释选项,并且决定是否需要再次获得选项。将其分为三种方法,一种用于获取选项,一种解释选项,一种将它们放在一起。这将更加灵活,更易于测试。

抓住每个标准词都太宽了。通过方法拆分,该选项是对方法的参数。您可以将异常更改为更具体的 grognn> grigenterror

def get_option
  input(I18n.t(:start_game_options, option1: OPTION_1, option2: OPTION_2, exit: EXIT))
end

def do_option(option)
  case option
  when OPTION_1 then wrapper(adapter_my_guess(input(I18n.t(:puts_guess, exit: OR_EXIT))))
  when OPTION_2 then wrapper(adapter_give_hints)
  else
    raise(ArgumentError, WRONG_OPTION)
  end
end

def choose_option
  do_option(get_option)
rescue ArgumentError
  choose_option
end

现在,每个都可以进行单位测试,而无需模拟整个过程。例如,我们需要在 select_option 中测试的只是它是否有一个选项,尝试使用它并进行重试。

describe '#choose_option' do
  context 'with a good option' do
    it 'gets and does the option once' do
      option = double

      expect(adapter).to receive(:get_option)
        .and_return(option)
      expect(adapter).to receive(:do_option)
        .with(double)

      adapter.choose_option
    end
  end

  context 'with a bad option' do
    it 'gets and does the option again' do
      good_option = double
      bad_option = double

      # This will raise an ArgumentError.
      expect(adapter).to receive(:do_option)
        .with(bad_option)
        .and_call_original

      # This will not.
      expect(adapter).to receive(:do_option)
        .with(good_option)

      # First use the bad option, then the good one.
      expect(adapter).to receive(:get_option)
        .and_return(bad_option, good_option)

      adapter.choose_option
    end
  end    
end

我们不需要知道什么 do_option nor get_option 可以测试 select_option ,可以完全模拟它们。 do_option get_option 可以单独测试。

describe '#do_option' do
  subject { adapter.do_option(option) }

  context 'with option 1' do
    let(:option) { described_class.OPTION_1 }

    it 'guesses' do
      expect(adapter).to receive(:adapter_my_guess)
      subject
    end
  end

  context 'with option 2' do
    let(:option) { described_class.OPTION_2 }

    it 'gives hints' do
      expect(adapter).to receive(:adapter_give_hints)
      subject
    end
  end

  context 'with the wrong option' do
    let(:option) { "basset hounds got long ears" }

    it 'raises' do
      expect { subject }.to raise_error(ArgumentError)
    end
  end
end

那是基本方法。

except(adapter).to receive(:adapter_my_guess) says adapter will receive one and only one call to adapter_my_guess. It's received two.

If that is correct, change your expectation to expect more calls by adding at_least(1).time.

If that is not correct, we'd need to know more about your code and test.


Some notes...

Do not use instance_variable_get and instance_variable_set in production code. Grabbing at other object's internal variables tangles up the code and makes it hard to change the object without unforeseen consequences. Make secret_code a proper accessor method.

choose_option does three things. It gets the option, it interprets the option, and it decides if it needs to get the option again. Split it into three methods, one to get the option, one to interpret the option, and one to put them together. That will be more flexible and easier to test.

Catching every StandardError is too broad. With the methods split, the option is an argument to a method. You can change the exception to be a more specific ArgumentError.

def get_option
  input(I18n.t(:start_game_options, option1: OPTION_1, option2: OPTION_2, exit: EXIT))
end

def do_option(option)
  case option
  when OPTION_1 then wrapper(adapter_my_guess(input(I18n.t(:puts_guess, exit: OR_EXIT))))
  when OPTION_2 then wrapper(adapter_give_hints)
  else
    raise(ArgumentError, WRONG_OPTION)
  end
end

def choose_option
  do_option(get_option)
rescue ArgumentError
  choose_option
end

Now each can be unit tested without having to mock the whole process. For example, all we need to test in choose_option is whether it gets an option, tries to do something with it, and retries.

describe '#choose_option' do
  context 'with a good option' do
    it 'gets and does the option once' do
      option = double

      expect(adapter).to receive(:get_option)
        .and_return(option)
      expect(adapter).to receive(:do_option)
        .with(double)

      adapter.choose_option
    end
  end

  context 'with a bad option' do
    it 'gets and does the option again' do
      good_option = double
      bad_option = double

      # This will raise an ArgumentError.
      expect(adapter).to receive(:do_option)
        .with(bad_option)
        .and_call_original

      # This will not.
      expect(adapter).to receive(:do_option)
        .with(good_option)

      # First use the bad option, then the good one.
      expect(adapter).to receive(:get_option)
        .and_return(bad_option, good_option)

      adapter.choose_option
    end
  end    
end

We don't need to know what do_option nor get_option does to test choose_option, they can be totally mocked. do_option and get_option can be unit tested separately.

describe '#do_option' do
  subject { adapter.do_option(option) }

  context 'with option 1' do
    let(:option) { described_class.OPTION_1 }

    it 'guesses' do
      expect(adapter).to receive(:adapter_my_guess)
      subject
    end
  end

  context 'with option 2' do
    let(:option) { described_class.OPTION_2 }

    it 'gives hints' do
      expect(adapter).to receive(:adapter_give_hints)
      subject
    end
  end

  context 'with the wrong option' do
    let(:option) { "basset hounds got long ears" }

    it 'raises' do
      expect { subject }.to raise_error(ArgumentError)
    end
  end
end

That's the basic approach.

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