Your example code expands to:
def subject # subject { create(:a) }
create(:a)
end
b = subject.b # this is where your `binding.pry` gets called, since it persists the record and does the validation
expect(b).to receive(:to_s) # this is too late to stub, as `to_s` was called already
subject.save # if I'm not mistaken, it's a no-op, since the object is not dirty
I'm struggling to understand the business meaning of `to_s` on `B`, and what's its implementation, specifically how it can return something falsey.
I'd suggest testing side effects, i.e.:
describe 'validations' do
subject(:a) { A.new } # or `build_stubbed(:a)`
it 'fails when an associated B record inspects as false' do
allow(a.b).to receive(:to_s).and_return(nil) a.validate!
expect(a.valid?).to be false
end
it 'passes when an associated B record inspects as true' do
allow(a.b).to receive(:to_s).and_return(true) a.validate!
expect(a.valid?).to be true
end
That way, you check both branches of `validate_my_field` (assuming you don't have to cover `super`, and it fails the validation).
I also tend to think that persisting might be unnecessary to validate objects.
Please let me know what you think, but in any case, the more context you provide the better.