Using contracts.ruby With RSpec. Part 2

contracts.ruby, design-by-contract, rspec, ruby

Remember Using contracts.ruby With RSpec ?

RSpec mocks violate all :class contracts because is_a?(ClassName) returns false for mock. That post describes 2 possible solutions:

  • stub :is_a?: allow(my_double).to receive(:is_a?).with(MyClass).and_return(true), or
  • use contracts-rspec gem, that patches instance_double RSpec helper.

Custom validators

Since custom validators have finally landed here: egonShiele/contracts.ruby#159, now you can just override :class validator to accept all RSpec mocks:

1
2
3
4
5
6
7
# Make contracts accept all RSpec doubles
Contract.override_validator(:class) do |contract|
  lambda do |arg|
    arg.is_a?(RSpec::Mocks::Double) ||
      arg.is_a?(contract)
  end
end

Now, RSpec mocks will not violate all the :class contracts.

More information can be found here: Providing your own custom validators.

Additionally this refactoring enabled valuable speed optimization for complex contracts - validators for them will be evaluated only once and memoized.

Links

Thanks!

If you have any questions, suggestions or just want to chat about how contracts.ruby is awesome, you can ping me on twitter @tdd_fellow. If you have any issues using contracts.ruby you can create issues on corresponding github project. Pull requests are welcome!

Comments on hackernews.

Happy coding! @tdd_fellow on twitter.