3

Foo.barメソッドの動作をテストせずに、次の例で呼び出されていることをテストするにはどうすればよいbarですか (既に他の場所でテストされています)。

# Code
class Alpha
  def process
    Foo.bar
  end
end

次の仕様は、これまでのところ私が持っているものです。残念ながら、このアプローチでは、Foo がプロジェクトの他の場所で既に定義されているため、「クラスは既に定義されています」という警告がスローされます。

 # Spec
 let(:alpha) { Alpha.new }
 let(:klass) { MiniTest::Mock.new }

 subject { alpha.process }

 it "calls Foo.bar" do
   klass.expect(:bar, '')     # Define method call expectation
   Foo = klass                # Redefine Foo as a mock object
   subject                    # Run method being tested
   klass.verify               # Confirm method was called
 end

Fooクラスは外部依存であるため、テストをクラスに依存させたくありませんFoo.bar。また、任意に変更される可能性があるため、の応答値をテストしたくありません。

4

2 に答える 2

6

このようなクラスをモックアウトするには、次のようにインジェクションポイントを挿入する必要があります。

class Alpha
  def initialize(opts = {})
    @foo_class = opts[:foo_class] || Foo
  end

  def process
    @foo_class.bar
  end
end

これが機能するのは、クラス名がRubyの定数であり、他の値と同じように割り当てることができるためです。Fooしたがって、のクラスへの呼び出しをハードコーディングするのではなくAlpha、新しい@foo_classインスタンス変数が指すものすべてでメソッドを呼び出すことになります。Fooほとんどの場合、他の何かを渡さない限り、これはクラスのままです。私は通常、ここで行ったように、このようなモックパラメーターをオプションのパラメーターとして非表示にします。また、それらへの参照は、技術的にはパブリックAPIと見なされるものの一部ではないため、エンドユーザーを対象としたドキュメントには含めません。

次に、テストでは、次のAlphaようにオブジェクトを初期化できます。

fooClassMock = MiniTest::Mock.new
fooClassMock.expect(:bar, '')
alpha = Alpha.new(:foo_class => fooClassMock)

そして、あなたはあなたが探している結果を得るはずです。

于 2012-12-28T06:03:03.480 に答える
3

これは少し古い質問であることは承知していますが、テストを容易にするためにビジネス コードを変更する必要のない解決策を探していたので、解決策を思いついたと思います。

Rails を使用している場合でも、 に追加してから に追加する必要がgem "minitest"あります。 Gemfilerequire "minitest/mock"test_helper.rb

it "calls Foo.bar" do
  bar_is_called = false
  bar_lambda = ->{
    bar_is_called = true
  }

  Foo.stub(:bar, bar_lambda) do
    Alpha.new.process
  end
  bar_is_called.must_equal true
end

.stub戻り値を渡すことができます。または、に応答するものを渡すと.call、それを呼び出します.call(スタブ メソッドのドキュメント)。この例では。bar_lambdaが呼び出され、 の値が変更されますbar_is_calledFoo.barこれは、それが呼び出されたことを確認します。

テスト構文でも同様に機能します。

test 'Foo.bar is called' do
  bar_is_called = false
  bar_lambda = ->{
    bar_is_called = true
  }

  Foo.stub(:bar, bar_lambda) do
    Alpha.new.process
  end
  assert bar_is_called
end
于 2016-09-27T15:09:22.713 に答える