sarri xx
sarri xx

Reputation: 43

How to test if an ActiveRecord association is being used with RSpec?

What is the best way to see if their Active Record associations are no longer being used? How can I write a rspec test to see if the association is no longer being used?

I have to refactor someone else's (who is no longer a part of the project) Rails model. Currently, I am using atom to see if the associations are being called elsewhere in the repository, but I know this isn't the best way to do it. I want to build unit tests for the model, but am not completely sure on how to approach this for associations. Currently, I am using shoulda matchers and factory_girl_rails.

Upvotes: 0

Views: 1715

Answers (3)

Greg
Greg

Reputation: 6628

I think this is the problem as old as the software design itself.

How to check if something is not used anymore?

It's a problem in dynamic languages like ruby. There are few ways to address that.

1. Cover all your app with end-to-end tests

Usually, it's difficult to have the 100% coverage, and this solution might not be readily available to you

2. Delete the usage and see if everything still works

Like point 1, but manual. Very difficult in bigger systems, and usually you don't have every feature documented.

3. Monkeypatch and log usages

For associations this may be sth like:

has_namy :foos

def foos
  log 'foos is used!'
  super
end

But as @chumakoff said here https://stackoverflow.com/a/51982936/299774 the association may be used in few more places. So you'd need to make some investigation to find all the places to hook your logging into.

This solution also has a drawback: how long should you wait until you declare the association unused? Should you wait half a year? What if nobody used it for that long, but there's a feature used once a year, and it got broken?

So, what do I do?

It depends on the size of the app and criticality etc. Sometimes you can risk it, sometimes you decide to live with some not used code. Or you get more creative like in here Find unused code in a Rails app.

Or you could disable this association for a fraction of users and watch for exceptions coming to wherever you aggregate logs/exceptions.

Maybe you should check the DB if there's anything in the database? If not - can you find a migration that removed all the stuff from there? Can you contact the author?

Upvotes: 0

chumakoff
chumakoff

Reputation: 7024

There are at least two ways the association might be used:

  1. Explicitly - calling on an object.

    object.association_name
    

    In this case it is easy to track:

    expect_any_instance_of(Model).to_not receive(:association_name)
    

    Another question is where to place this expectation in your test structure.

  2. Implicitly - in complex queries or for associated data preloading.

    Model.all.joins(:association_name)
    Model.all.includes(:association_name)
    

    In this case it is very hard to track.

I suggest another approach:

Do not track the association usage, instead check if tests pass when the association is removed. You can safely remove the association for the test environment.

For example, you can replace this:

has_many :association_name

with this:

unless Rails.env.test?
  has_many :association_name
end

This will not break anything and will raise an error only when running tests and only if the association is being used somewhere.

Upvotes: 1

vinyl
vinyl

Reputation: 559

Rspec uses reflect_on_association for this purpose. An example would be

it 'has many associations' do
    assc = Model.reflect_on_association(:other_model)
    expect(assc.macro).to eq :has_many
end

Upvotes: 0

Related Questions