To use or not to use assert_predicate with minitest in Ruby

Reading time: 3 minutes

Recently RuboCop started to blame my assert something.booked? style tests in minitest and telling me this:

Minitest/AssertPredicate: Prefer using `assert_predicate(something, :booked?)`.

I’ve looked for the corresponding Pull Request and also checked the final Rubocop Minitest Style Guide: Assert Predicate.

According to the documentation, we can read:

Use assert_predicate if expecting to test the predicate on the expected object and on applying predicate returns true. The benefit of using the assert_predicate over the assert or assert_equal is the user friendly error message when assertion fails. – assert_predicate

Compare the difference

First I try the simple assert and let the test fail

test 'something must be booked before it can be used' do
  something =
  assert something.booked?

# resulting fail output
Expected true to not be truthy.

Now the version with assert_predicate:

test 'something must be booked before it can be used' do
  something =
  assert_predicate something, :booked?

# resulting fail output
Expected <something> to be booked?

If you compare the two outputs, you will see, that using assert_predicate produces a more readable output, what is also mentioned in the documentation.

How to proceed with such a new rule?

As this is a pretty new (March 2022) RuboCop rule in rubocop-minitest, it will hit a lot of projects. For me using plain assert where it is useful like in assert something.booked? is a rule of thumb, as I left RSpec, because it has for almost everything a separate command, which I became tired to learn or lookup. Well, how to proceed?

You can ignore it

You can just ignore the rule and add these lines to your .rubocop.yml file in your project:

  Enabled: false

  Enabled: false

Remember to add both rules for assert_predicate and refute_predicate or RuboCop will blame refute something.booked? too.

You can accept the new rule

If you accept this new rule, it is good to have an up-to-date project with all other rules being already applied. To apply all current rule just run:

rubocop -A

All new rules will be applied to all files, which may be more than the rules you wanted to be applied.

As projects for many reasons may be:

You can apply only these two relevant to your project and ask RuboCop to fix them for you:

bundle exec rubocop -A --only Minitest/AssertPredicate
bundle exec rubocop -A --only Minitest/RefutePredicate

Afterward commit them with a corresponding explanation, as it may hit a lot of test files.

My current approach

Most of the time I used simple assert with ruby code and not test specific language (like it is more common in RSpec). I thing a simple assert followed by good named ruby code more readable and less to think about while trying to understand test code.

In this case assert_predicate and refute_predicate produce a better output on a failed test, but check the same as a simple assert would do. That’s why I will use assert_predicate and refute_predicate now.