Writing a Basic RSpec Example
Fast recall
Quick revision
Core answer
RSpec.describe, states one behaviour in an it block, prepares only the data that behaviour needs, performs the action, and checks the observable result with expect(...).to matcher. In Rails, use the matching spec type or conventional folder, such as spec/models for a model and spec/requests for an HTTP endpoint. Each example should be independent and its description should still make sense in the test report.Whether you know RSpec is an expressive BDD framework (describe/it/expect), with let/before, and is an alternative to Minitest.
Overusing mocks/stubs (tests pass but don't test real behavior) — prefer real objects/integration where feasible.
RSpec: expressive BDD framework. describe/it/expect(x).to eq. let (lazy), before (setup). bundle exec rspec. Alternative to Minitest.
Interview-ready guide
Interview answer
Start with RSpec.describe for the class, request, or feature under test. Inside it, an it block names one observable result. A description such as it "applies the supplied tax rate" should read clearly in the test report and say what contract failed without exposing a private method.
Prepare only the input this behaviour needs, call the public method, and check the result with expect(actual).to matcher. A specific matcher such as eq(118) explains the expected value better than a broad truthy check. The runnable example leaves the decisive subtotal and tax rate beside the expectation.
In Rails, the spec type controls the helpers available to an example. Model specs normally live in spec/models; request specs in spec/requests can issue HTTP calls and inspect the response. Folder inference is common, while metadata such as type: :request can state the boundary explicitly.
let and before can remove setup repeated across a group, but they should not hide the values that explain one result. Each example must run independently and give the same result alone or in the full suite. Files, clocks, queues, random values, and external services still need deliberate control beyond database isolation.
Writing a Basic RSpec Example
Direct Answer
A basic RSpec example names the subject with RSpec.describe, states one behaviour in an it block, prepares only the data that behaviour needs, performs the action, and checks the observable result with expect(...).to matcher. In Rails, use the matching spec type or conventional folder, such as spec/models for a model and spec/requests for an HTTP endpoint. Each example should be independent and its description should still make sense in the test report.
Deep Dive & Architecture
RSpec's hierarchy becomes part of the failure message. The outer group identifies the subject, an optional context describes a meaningful condition, and it names the expected behaviour. Nesting is helpful only when each level changes the meaning; folders of one-line contexts make a reader reconstruct a sentence across the whole file.
Setup is evaluated before an expectation can teach anything. Values defined with let are lazy and memoised within an example, while before runs setup at the chosen scope. Use them to remove noise, not to conceal the decisive input. A local variable is often clearest when only one example needs it.
Matchers should express the contract at the correct boundary. Check a return value for a calculation, persisted state for a command, and an HTTP status or response body for a request. Stubbing the method under test or asserting every internal call can let implementation changes break tests even when user-visible behaviour remains correct.
Examples must not depend on execution order or state left by another test. Rails database isolation helps, but files, queues, time, random values, and external services still need deliberate control. Independence makes a single focused run mean the same thing as the full suite.
Code Example
RSpec.describe Invoice, type: :model do
describe '#total' do
it 'applies the supplied tax rate' do
invoice = Invoice.new(subtotal: 100, tax_rate: 0.18)
total = invoice.total
expect(total).to eq(118)
end
end
end
Common Mistakes & Pitfalls
Overusing mocks/stubs (tests pass but don't test real behavior) — prefer real objects/integration where feasible.
Check your understanding
Answer these without looking back at the article.
- What is the difference between `describe`, `context`, and `it`?
- When should setup stay inside an example instead of a `before` hook?
- Why should a test prefer public behaviour over private method calls?
Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.