0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

shared examplesとは

Posted at

shared exampleはクラスとモジュールの振る舞いを記述させる

Shared examples let you describe behaviour of classes or modules.

When declared, a shared group’s content is stored.

他のexample groupのコンテキストでのみ実行に必要な共有グループのいくつかのコンテキストを供給する

It is only realized in the context of another example group, which provides any context the shared group needs to run.

気になる単語

  • Shared examples、shared group
  • context、example group

このどれかを使ってshared_exampleを呼び出す

A shared group is included in another group using any of:

  include_examples "name"      # include the examples in the current context
  it_behaves_like "name"       # include the examples in a nested context
  it_should_behave_like "name" # include the examples in a nested context
  matching metadata            # include the examples in the current context

shared_exampleを使ったテスト

 RSpec.shared_examples "some example" do |parameter|
    \# Same behavior is triggered also with either `def something; 'some value'; end`
    \# or `define_method(:something) { 'some value' }`
    let(:something) { parameter }
    it "uses the given parameter" do
      expect(something).to eq(parameter)
    end
  end

  RSpec.describe SomeClass do
    include_examples "some example", "parameter1"
    include_examples "some example", "parameter2"
  end

動かしてみた 変数の上書きされている エラー

RSpec.describe SomeClass do
    include_examples "some example", "parameter1"
    include_examples "some example", "parameter2"
end
expected: "parameter1"
     got: "parameter2"

(compared using ==)


  0) User uses the given parameter
     Failure/Error: expect(something).to eq(parameter)

       expected: "parameter1"
            got: "parameter2"

       (compared using ==)

最初のテストは失敗する

You’re actually doing this (notice that first example will fail):

  RSpec.describe SomeClass do
    \# Reordered code for better understanding of what is happening
    let(:something) { "parameter1" }
    let(:something) { "parameter2" }

    it "uses the given parameter" do
      \# This example will fail because last let "wins"
      expect(something).to eq("parameter1")
    end

    it "uses the given parameter" do
      expect(something).to eq("parameter2")
    end
  end

上のコードを動かしてみた結果

expected: "parameter1"
     got: "parameter2"

(compared using ==)


  0) User uses the given parameter
     Failure/Error: expect(something).to eq("parameter1")

       expected: "parameter1"
            got: "parameter2"

       (compared using ==)

変数が上書きされているからエラーが起こったと考える

エラーが起こる原因

shared groupを含んだファイルを前にロードするためには厳格な名前規則が必要だ

WARNING: Files containing shared groups must be loaded before the files that use them. While there are conventions to handle this, RSpec does not do anything special (like autoload). Doing so would require a strict naming convention for files that would break existing suites.

同じコンテキスト内で複数回呼ぶと最後に呼ばれたやつが勝つ

WARNING: When you include parameterized examples in the current context multiple times, you may override previous method definitions and last declaration wins. So if you have this kind of shared example (or shared context)

上のエラーを回避

同じcontextで同じ名前のメソッドを複数宣言すると警告される

To prevent this kind of subtle error a warning is emitted if you declare multiple methods with the same name in the same context.

上の警告を防ぐためにinclude_examplesit_behaves_likeに置き換える

Should you get this warning the simplest solution is to replace include_examples with it_behaves_like, in this way method overriding is avoided because of the nested context created by it_behaves_like

どちらかを変えると両方通る

RSpec.describe User do
  include_examples "some example", "parameter1" # 以下2行同じコンテキスト内だと考える
  it_behaves_like "some example", "parameter2"
end

requireでファイルを要求する

The simplest approach is to require files with shared examples explicitly from the files that use them.

require ファイル名と書くと特定のパスから呼び出される

Keep in mind that RSpec adds the spec directory to the LOAD_PATH, so you can say require 'shared_examples_for_widgets' to require a file at #{PROJECT_ROOT}/spec/shared_examples_for_widgets.rb.

spec/support/にあるshared examplesを含むファイルを置き、...requireする

One convention is to put files containing shared examples in spec/support/ and require files in that directory from spec/spec_helper.rb:

Dir["./spec/support/**/*.rb"].sort.each { |f| require f }

同じファイルに全てあるときはshared groupを宣言するだけで良い

When all of the groups that include the shared group reside in the same file, just declare the shared group in that file.

感想

shared examplesは関数で、shared groupはshared examplesで使われるcontextを言うのだろう。

  • requireを使ってみる

  • include_examplesit_behaves_likeに置き換える

  • Dir["./spec/support/**/*.rb"].sort.each { |f| require f }を使ってみる

  • include_examples "name", it_behaves_like "name", it_should_behave_like "name", matching metadata の意味の使い分けを知りたい

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?