Spec Metadata

Current example

You can reference the example object, and access its metadata, using the block
argument provided to: itsubjectlet, and the beforeafter, and
around hooks.

RSpec provides a way to tag tests with metadata that provides additional information about the test. This metadata can be used to filter or organize tests and to provide additional context for the test.

Metadata is specified using the metadata method in RSpec. It takes a hash of key-value pairs where the key is a symbol that represents the metadata label and the value is the metadata value.

For example, consider the following RSpec test:

rubyCopy codeRSpec.describe MyClass do
  describe "#my_method", metadata: { type: :slow } do
    it "should take a long time to run" do
      # test code
    end
  end
end

In this example, we have tagged the #my_method test with metadata indicating that it is a :slow test. This metadata can be used to filter the test suite to only run :slow tests or to exclude :slow tests.

You can also specify multiple metadata labels for a test:

rubyCopy codeRSpec.describe MyClass do
  describe "#my_method", metadata: { type: :slow, author: "Alice" } do
    it "should take a long time to run" do
      # test code
    end
  end
end

In this example, we have added an additional :author metadata label to the #my_method test.

RSpec also provides built-in metadata labels that can be used to tag tests:

  • :focus: Indicates that the test should be focused and run exclusively.
  • :skip: Indicates that the test should be skipped.
  • :example_group: Specifies a custom label for the test group.

You can filter tests by metadata labels using the --tag or -t command line option. For example, to run only the :slow tests, you can use the following command:

bashCopy coderspec --tag type:slow

In summary, RSpec metadata allows you to tag tests with additional information that can be used to filter or organize tests and provide additional context for the test.

Access the `example` object from within an example

RSpec.describe "example as block arg to it, before, and after" do
  before do |example|
    expect(example.description).to eq("is the example object")
  end

  after do |example|
    expect(example.description).to eq("is the example object")
  end

  it "is the example object" do |example|
    expect(example.description).to eq("is the example object")
  end
end

RSpec.describe "example as block arg to let" do
  let(:the_description) do |example|
    example.description
  end

  it "is the example object" do |example|
    expect(the_description).to eq("is the example object")
  end
end

RSpec.describe "example as block arg to subject" do
  subject do |example|
    example.description
  end

  it "is the example object" do |example|
    expect(subject).to eq("is the example object")
  end
end

RSpec.describe "example as block arg to subject with a name" do
  subject(:the_subject) do |example|
    example.description
  end

  it "is the example object" do |example|
    expect(the_subject).to eq("is the example object")
    expect(subject).to eq("is the example object")
  end
end

WhenI run rspec spec/example_spec.rbThenthe example should pass

The Described class

If the first argument to the outermost example group is a class, the class is exposed to each example via the described_class() method.

In RSpec, the describe method is used to define a test suite, which groups together a set of tests that are related to a specific behavior or functionality of the code being tested. The argument to describe is typically the class or module being tested, and it can also include a string that describes the behavior being tested.

For example, consider the following RSpec test:

rubyCopy codeRSpec.describe MyClass do
  describe "#my_method" do
    it "should return the correct value" do
      # test code
    end
  end
end

In this example, we are testing a class called MyClass, and we have defined a test suite using the describe method. Within the test suite, we have defined a test for the #my_method method using the it method.

The describe block is used to provide context for the tests that are defined within it. By default, RSpec assumes that the argument to describe is a class or module being tested, and it uses the class name to provide context for the tests. In this case, RSpec will use the string "MyClass" as the context for the test suite.

If you provide a string as an additional argument to describe, RSpec will use that string to provide additional context for the tests. For example:

rubyCopy codeRSpec.describe MyClass, "when initialized" do
  describe "#my_method" do
    it "should return the correct value" do
      # test code
    end
  end
end

In this example, we have added the string "when initialized" as additional context for the test suite. This can make the test output more readable and provide additional information about the behavior being tested.

In summary, describe is used to define a test suite in RSpec, and it typically takes a class or module as its argument. The describe block is used to provide context for the tests defined within it, and it can include an additional string to provide more specific context for the tests.

Access the described class from the example

RSpec.describe Fixnum do
  it "is available as described_class" do
    expect(described_class).to eq(Fixnum)
  end
end

User-defined metadata

You can attach user-defined metadata to any example group or example. Pass a
hash as the last argument (before the block) to describecontext or it. RSpec supports many configuration options that apply only to certain examples or groups based on the metadata.

Metadata defined on an example group is available (and can be overridden) by any sub-group or from any example in that group or a sub-group.

In addition, you can specify metadata using just symbols. Each symbol passed as an argument to describecontext or it will be a key in the metadata hash, with a corresponding value of true.

In RSpec, user-defined metadata allows you to tag your tests with custom labels that provide additional information about the tests. This metadata can be used to filter or organize tests and to provide additional context for the test.

To define user-defined metadata, you can use the metadata method, which takes a hash of key-value pairs where the key is a symbol that represents the metadata label and the value is the metadata value.

For example, consider the following RSpec test:

rubyCopy codeRSpec.describe MyClass do
  describe "#my_method", my_custom_metadata: "foo" do
    it "should return the correct value" do
      # test code
    end
  end
end

In this example, we have tagged the #my_method test with user-defined metadata indicating that it has a my_custom_metadata label with the value of "foo". This metadata can be used to filter the test suite to only run tests with the my_custom_metadata label.

You can also specify multiple user-defined metadata labels for a test:

rubyCopy codeRSpec.describe MyClass do
  describe "#my_method", my_custom_metadata: "foo", author: "Alice" do
    it "should return the correct value" do
      # test code
    end
  end
end

In this example, we have added an additional author metadata label to the #my_method test.

You can filter tests by user-defined metadata labels using the --tag or -t command line option, similar to built-in metadata labels. For example, to run only the tests with the my_custom_metadata label, you can use the following command:

cssCopy coderspec --tag my_custom_metadata

In summary, user-defined metadata allows you to tag your tests with custom labels that provide additional information about the tests. This metadata can be used to filter or organize tests and to provide additional context for the test.

Define group metadata using a hash

RSpec.describe "a group with user-defined metadata", :foo => 17 do
  it 'has access to the metadata in the example' do |example|
    expect(example.metadata[:foo]).to eq(17)
  end

  it 'does not have access to metadata defined on sub-groups' do |example|
    expect(example.metadata).not_to include(:bar)
  end

  describe 'a sub-group with user-defined metadata', :bar => 12 do
    it 'has access to the sub-group metadata' do |example|
      expect(example.metadata[:bar]).to eq(12)
    end

    it 'also has access to metadata defined on parent groups' do |example|
      expect(example.metadata[:foo]).to eq(17)
    end
  end
end

Define example metadata using a hash

RSpec.describe "a group with no user-defined metadata" do
  it 'has an example with metadata', :foo => 17 do |example|
    expect(example.metadata[:foo]).to eq(17)
    expect(example.metadata).not_to include(:bar)
  end

  it 'has another example with metadata', :bar => 12, :bazz => 33 do |example|
    expect(example.metadata[:bar]).to eq(12)
    expect(example.metadata[:bazz]).to eq(33)
    expect(example.metadata).not_to include(:foo)
  end
end

Override user-defined metadata

RSpec.describe "a group with user-defined metadata", :foo => 'bar' do
  it 'can be overridden by an example', :foo => 'bazz' do |example|
    expect(example.metadata[:foo]).to eq('bazz')
  end

  describe "a sub-group with an override", :foo => 'goo' do
    it 'can be overridden by a sub-group' do |example|
      expect(example.metadata[:foo]).to eq('goo')
    end
  end
end

Less verbose metadata

RSpec.describe "a group with simple metadata", :fast, :simple, :bug => 73 do
  it 'has :fast => true metadata' do |example|
    expect(example.metadata[:fast]).to eq(true)
  end

  it 'has :simple => true metadata' do |example|
    expect(example.metadata[:simple]).to eq(true)
  end

  it 'can still use a hash for metadata' do |example|
    expect(example.metadata[:bug]).to eq(73)
  end

  it 'can define simple metadata on an example', :special do |example|
    expect(example.metadata[:special]).to eq(true)
  end
end