runtimeanalyz.ing

← All capabilities

unit_test_candidates

CLI · MCP Pro

Which methods to test first. Every recorded method ranked by how many distinct callers it has and how many calls away the nearest spec is, to choose which untested code gets a test first.

In your app

Checkout
debit ( account, Account amount Money )
Finance::Accounts 14 callers
module Finance
  class Accounts
    def debit(account, amount) = …
  end
end
Refund
debit
Payroll
debit
SettlementJob + 10 more
debit

In your specs

any spec example
distance ∞
Finance::Accounts#debit never reached
First Finance::Accounts#debit fan-in 14 · no spec reaches it
Fan-in comes from the distinct callers in recorded runs, and distance from the spec-stamped call trees. The method with the most callers and no spec reaching it is ranked first.

The problem

You’ve inherited an app with patchy tests, or you’ve decided the suite needs to catch more. There is more untested code than time to test it, so you need an order to work in.

A coverage report lists the uncovered methods sorted by file name. It gives Enrollment#withdraw the same weight as Finance::Accounts#debit, which checkout, refunds, fees and transfers all go through. If debit is wrong, everything that moves money is wrong, and the coverage report shows it as one uncovered line among the others.

Mutation testing has a similar problem. Mutant is slow, so running it evenly across the app spends most of its time on code that little else depends on.

The fix

Rank every recorded method by how much depends on it and how close a spec gets:

$ ra unit_test_candidates app/

test these first
· 165 methods
  fan-in  distance  method
      12         1  Money#cents
       7         0  Money#initialize
       6         0  Invoice#number
       6         0  Invoice#total
       6         1  Money#to_s
       5         0  Finance::Accounts#initialize
       5         0  Finance::Accounts#debit
  … 158 more
       1  ∞         Enrollment#withdraw
       1  ∞         Cancellation#call
       0  ∞         DashboardController#show

Fan-in is the number of distinct callers across your specs and app runs. Distance is the fewest calls from a spec example’s body to the method, so 0 means a spec calls it directly and ∞ means no spec reaches it. Finance::Accounts#debit has five callers and spec/finance/accounts_spec.rb calls it directly. Enrollment#withdraw has one caller in the recorded traffic, Cancellation#call, and no spec reaches it, so it goes first. Ask how_to_reach for the setup and write the spec, then run mutant on the methods at the top of the same list instead of on the whole app.

How it works

  1. Every recorded call edge includes its caller’s method. A method’s fan-in is the number of distinct callers it has across your app runs and your specs.
  2. Each call tree is stamped with the entry point that started it, which is a spec example or an app run. A method’s distance is the shallowest depth at which a tree started by a spec reaches it. A method that specs reach five calls deep and no shallower is barely tested, and a method no spec reaches is untested.
  3. Methods are ranked by higher fan-in first. Within one fan-in, methods a spec reaches come first, nearest first, and methods no spec reaches come last.

The ranking needs a recording of the code being used. If the app has no tests, record the app running in development, staging or production.

Run it on your app

The output on this page comes from our example Rails app, and it is regenerated whenever a tool changes. These are the commands behind it. On your own app, run ra record first, then put your own class, method or file in their place.

ra unit_test_candidates app/

The untested method is app/models/enrollment.rb:47, and its one caller is in app/services/cancellation.rb.

Reading the result

  • Distance measures how close a spec gets to a method. A spec that calls debit and checks nothing still counts as reaching it. The report has no information about what a test asserts.
  • Fan-in counts callers. A method with one caller can still be the most important one to test, like the one place you charge a card, so treat the ranking as an order to look in.
  • The report lists every recorded method. There is no filter for the ∞ rows yet, so you find the untested methods by reading the distance column.

Every tool reads the same recording. What gets recorded and how far to trust an answer are on the questions page.

how_to_reach

MCP · CLI Pro

The setup a method needs. The collaborators and the call path that put an object into the state a method needs, taken from a recorded run. Use it to write setup for tests that use real objects in place of doubles.

See more →

testing_pyramid

CLI · MCP Pro

Boundaries crossed through doubles alone. The calls between classes that your specs make through a double alone, with how many specs stub each one and how often your recorded app traffic made it for real, plus the number of examples in each spec directory.

See more →

how_far_it_reached

CLI · MCP Pro

How far each spec example reached. For each spec example, the number of classes its recorded call tree touched and how deep the calls went. A unit spec that reaches fourteen classes is an integration test.

See more →