3

I know be false will just return true if the expected value is a pure false value, wherease be_falsey will return true if the expected value is either false or nil.

However, I fail to understand when would I use one or the other. I fail to see an example where be_falsey would be more useful than be false.

Hommer Smith
  • 26,772
  • 56
  • 167
  • 296
  • 1
    [Consider renaming `be_true` and `be_false` to `be_truthy` and `be_falsey`](https://github.com/rspec/rspec-expectations/issues/283) – Roman Kiselenko Nov 17 '14 at 17:58
  • I take it you've read through [this](https://github.com/rspec/rspec-expectations/issues/283) ? – Anthony Nov 17 '14 at 17:59

2 Answers2

4

There are lots of situations in Ruby where you get a nil result and want to treat it like false. For example, suppose we have a method that handles an options hash, and we want the absence of an option to be the same as the option set to false:

def verbose?(opts)
  opts[:verbose]  
end

opts = { verbose: false }
expect(verbose?(opts)).to be_falsey # => PASS

opts = { verbose: true }
expect(verbose?(opts)).to be_falsey # => FAIL

opts = {}
expect(verbose?(opts)).to be_falsey # => PASS

Obviously this is a simplistic example (you could argue that verbose? should always return true or false), but similar scenarios are common in Ruby.

Jordan Running
  • 102,619
  • 17
  • 182
  • 182
  • 1
    Small style point, though: Boolean methods should return true or false, not nil. So when testing boolean methods (those that end in `?`), use `be(true)` or `be(false)`, not `be_truthy` or `be_falsey`. – armchairdj Aug 26 '22 at 19:12
0

One example I can think of is for a unit test for a method. The method would be used in such a way that you are not really interested in the result, but only whether it is truthy/falsey.

Consider a method that checks if there is a record with a given value is in the db:

Class Foo
  def self.has_value? value
    Foo.find(value: value)
  end

This method would be used as:

if Foo.has_value?(value)
   ...

Now, you could write a test like this:

let(:foo ){ create :foo )
expect(Foo.has_value?(1)).to == foo

But this obscures the intent of the method. The method's intent is not to find a foo. It is to tell you whether a foo with a given value exists or not.

To express the intent of the method it might be better to use

expect(Foo.has_value(1).to be_truthy
expect(Foo.has_value(2).to be_falsey

In Rails, if model.save is often used. This is the same pattern.

B Seven
  • 44,484
  • 66
  • 240
  • 385