runtimeanalyz.ing ● early access · sign-up open

← All capabilities

how_to_reach

MCP free

Reach any method. The collaborators and call path that get an object into the state a method needs, taken from a real run. Setup for tests that use real objects instead of doubles.

billing_spec.rb:31 recorded run
The shortest recorded path to Invoice#total, oldest call first. Each argument is an object built earlier on the path.
Account.new ( plan: Plan )
Account built
RateTable.for ( account: Account )
RateTable built
Invoice.new ( account:, Account rate_table: RateTable )
Invoice built
The same object receives all three calls, in this order.
add_line ( item:, LineItem quantity: Integer )
total
total Money
Classes and order come from the recording. The values are yours to choose: the recording keeps LineItem and Integer, never which line item or how many.

The problem

If you’d rather test with real collaborators than doubles, the cost is setup. To call Invoice#total for real you need an Invoice, which needs line items and a rate table, which need an account. Nothing tells you which of those are required or what order to build them in, so you read the code, guess, and debug the guess.

That setup tax is the main reason people reach for doubles when they’d rather not.

The fix

Your agent asks while writing an integration spec:

how_to_reach("Invoice#total")
→ {
  path: [
    "Account.new(plan: Plan)",
    "RateTable.for(account: Account)",
    "Invoice.new(account: Account, rate_table: RateTable)",
    "Invoice#add_line(item: LineItem, quantity: Integer)",
    "Invoice#total"
  ],
  seen_in: "spec/requests/billing_spec.rb:31"
}

It turns that into setup that uses real objects throughout:

account    = Account.new(plan: Plan.new(:standard))
rate_table = RateTable.for(account:)
invoice    = Invoice.new(account:, rate_table:)
invoice.add_line(item: LineItem.new(sku: "A1"), quantity: 2)

expect(invoice.total).to eq(Money.new(2_400, "GBP"))

The classes and call order come from the recording. The values are yours: the recording keeps class names, never your data.

How it works

The recording keeps object identity. how_to_reach finds a recorded call to the target method, takes its receiver, and walks backwards through the call tree to where that object was built and every call made on it before the target. It does the same for each argument that was passed along the way. Of all the recorded ways to reach the method, it picks the shortest, and names the spec example or run it came from.

Limits

  • Classes, not values. It knows add_line was called with a LineItem and an Integer. Which line item and how many are up to you.
  • Only paths that ran. If the state a method needs was only ever reached through code you didn’t record, there’s no path to offer.
  • Shortest isn’t always simplest. The shortest recorded path might go through a factory or a service object. You can ask for the paths that avoid a given class.

testing_pyramid

CLI · MCP free

The boundaries your pyramid misses. Seams that are only ever crossed through a double, never for real, mapped onto your testing pyramid. Record production too and they're ranked by traffic.

See more →

verify_mock

CLI · LSP · MCP · CI free

Catch a lying mock. A stub that passes green but returns something the real collaborator never would. Mutation testing can't see it. The recording can.

See more →

observed_shape

CLI · LSP · MCP free

The observed contract. The messages your code actually sends to a value, read from real runs. The interface a call depends on, whether or not anyone declared it.

See more →