Techioz Blog

メソッドを main:Object にモックする最良の方法は?

概要

私たちは inspec フレームワークをよく使用します。

これは次のようなコードを推奨しており、多くのコードがあります。

https://docs.chef.io/inspec/inputs/#a-simple-example からのrock_critic/controls.rb:

# Set a default value for an input.  This is optional.
input('amplifier_max_volume', value: 10)

control 'Big Rock Show' do
  describe input('amplifier_max_volume') do    # This line reads the value of the input
    it { should cmp 11 } # The UK'S LOUDEST BAND
  end
end

入力.yml:

amplifier_max_volume: 11

これは次のように実行されます。

inspec exec rock_critic --input-file input.yml

inspec ラッパーの代わりに通常の Ruby を使用して、このコードをさまざまなシナリオ (ファイルなどのさまざまなソースからのペットのリストや実行時に作成されるペットのリストなど) で実行したいと考えています。つまり、ruby rock_critic/controls.rb

しかし、それを行うと、次のようになります。

$ ruby ./controls/controls.rb                                                                                                                           12:14:45
./controls/controls.rb:2:in `<main>': undefined method `input' for main:Object (NoMethodError)
$

なので、タイトルか語彙を間違えているかもしれませんが、 グローバルに定義されている input() のようなメソッド (main:Object) をモックする最良の方法は何ですか?

理想的には、別のテスト (describe、it など) を用意し、さまざまな入力を input() に渡したいと考えています。

ミックスインなどを試してみましたが、うまくいきません。良い例はありますか?おそらく私たちは何か間違ったことをしているのでしょう。

より良い説明になることを願っています、ありがとう!

私が使用してきたハックは、オブジェクトにモンキーパッチを適用することです。

    require 'minitest/autorun'


    input_hash = {
      'amplifier_max_volume' => 12
    }


      Object.define_method(:input) { |key, **opts| input_hash[key] }

      require_relative 'rock_critic/controls.rb'

残念ながら、これは完全に正しくないようで、input() に異なる値を指定するのは簡単ではありません。

解決策

input() は InSpec DSL によって提供されるメソッドであり、Ruby のグローバル関数ではないため、問題に直面しています。 Ruby でコードを直接実行しようとすると、input() を認識できません。考えられる回避策は、カーネル モジュールでモック メソッドを定義するか、実際の inspec コマンドを使用してコードの実際の動作をテストすることです。