RubyMoney/money-rails — pull request #255 by georgemillo (2014-12-18 22:13:06+00:00)
Title: monetize matcher matches nullable model attribute when tested instance h...

...as a non-nil value

Not sure what purpose the line `matched &&= actual.send(money_attr).nil?` was serving - the original test suite still passes without it.

The behaviour of the `monetize` matcher seems strange in general, as it's dependent on the state of the particular instance of the model it's being tested against rather than testing against the model as a whole. E.g. in a spec like this:

class Product
monetize :price_Cents
end

describe Product do
let(:product) { Product.new(price_cents: whatever) }

it { expect(product).to monetize(:price_cents) }
end

... whether the spec passes or fails depends on the specific value of "whatever", which doesn't really make sense as the attribute *is* monetized and the test should pass no matter what.

A better approach would be how shoulda-matchers does it:

describe Product do
let(:product) do
Product.new(
name: "present",
description: nil,
price_cents: 15_00
)
end

subject { product }

it { is_expected.to validate_presence_of(:name) }
# Doesn't care whether the attribute is present in this particular instance,
# only whether the class has the validation:
it { is_expected.to validate_presence_of(:description) }
# This would be a nicer approach for the monetize matcher:
it { is_expected.to monetize(:price_cents) }

describe "it works when the subject is the class itself too (i.e. the default subject)" do
subject { Product }
# This will pass:
it { is_expected.to validate_presence_of(:name) }
# Would be nice if this passed too:
it { is_expected.to monetize(:price_cents) }
end
end

My PR should bring `monetize`'s behaviour a bit closer to the "shoulda-matchers" way of doing things - what do you think? If you agree with the approach I'll see if I can make it work in a similar way for other test cases.