psyho / bogus

Fake library for Ruby
Other
359 stars 14 forks source link

Standard library parameters verification fails #67

Closed groyoh closed 9 years ago

groyoh commented 9 years ago

I recently had an issue using Bogus when trying to mock Object.const_get { Array } without specifying any parameter.I had specs passing with ruby and jrbuy but failling with rbx. I later figured out that this should not work at all (https://www.relishapp.com/bogus/bogus/docs/safe-stubbing) since const_get take two parameters but strangely it works with ruby and jruby. The reason is that Object.method(:const_get).parameters returns [[:req, :name], [:opt, :inherit]] on rbx but [[:rest]] on ruby and jruby. So Bogus assumes that it takes any number of parameters which should not be the case since Object.const_get(:Array, true, 1) would raise an ArgumentError. I tried with different methods of Object and it seems that every method that take an optional parameter would behave the same way. I assume that this may be the case with any standard library method that takes an optional argument.

psyho commented 9 years ago

Bogus does not examine the body of the method to learn whether it will raise an ArgumentError or not. It can only look at the method signature, and if the signature says the method takes any number of arguments, than that's what Bogus has to go with.

One thing you might consider in your tests is following the "Only Mock Types You Own" rule (introduced here). Since Object#const_get is not a method which implementation you control, you probably should not mock it. Instead you might want to introduce an abstraction that will call to const_get and integration test this behavior (which would catch the potential inconsistencies between JRuby, RBX and MRI) and mock that abstraction in the tests for the objects that use it.

I'm closing this ticket for now. If you feel like there is some kind of improvement to Bogus that I could make to support your use case, please feel free to re-open it or create a new issue.

groyoh commented 9 years ago

Stubbing Object#const_get in my case was not actually for mocking/stubbing purpose but that's not important. You state that bogus can only look at the method signature, but the thing is that the method signature returned by Object.method(:const_get).parameters # => [[:rest]] does not match its real signature since calling Object.const_get with 0 or more than two arguments would raise ArgumentError. This might be an issue with Ruby and Jruby, but I thought it was worth mentioning. Maybe it could be added in the docs that stubbing standard library objects might lead to errors.

Anyway, thanks for taking some time to answer me. :smile: