Testing rubys initialize
October 6th, 2014
In /ruby you have a lot of flexibility in writing code, this includes possibility to not initialize
an object.
I use this for testing my initializers, here are some examples how to do it.
Lets start with ruby class:
class TestMe attr_reader :value def initialize(value = nil) @value = value end end
It’s a simple example where only initialize
can set a value
, usually you use more advanced code, but this is just a minimal example.
Now lets test it:
describe TestMe do subject do TestMe.allocate end it "has default value" do subject.send :initialize subject.value.must_equal nil end it "sets value" do subject.send :initialize, 3 subject.value.must_equal 3 end end
For more real live examples of allocate check
- https://github.com/remote-exec/ruby-hooks/blob/master/test/ruby/hooks/hook_test.rb
- https://github.com/mpapis/contributors_stats/blob/master/test/contributors_stats/formatter_test.rb
- https://github.com/rvm/pluginator/blob/master/test/pluginator/autodetect_test.rb
- https://github.com/lsegal/yard/blob/master/spec/server/router_spec.rb
@Nando Vieira Exactly!
@Michal That’s extremely bad practice to
allocate
theninitialize
, the sole reason being to make it clear you’re testing #initialize. Your client code will never look like this (hopefully) so why should your specs? Any Ruby dev knows that Class#new calls allocate and initialize, no need to decompose it in your specs. Here’s how I would do it:https://gist.github.com/Roman2K/c72060a19161ae077b78
This simple. Yes, Ruby is flexible, so much so that people make contrived uses of all these tools, losing sight of simplicity and the principle of least surprise (the very one embraced by Matz originally).
@Jeremy
i do not need it, I more feel like it is the right way, getting the object before
initialize
and testing theinitialize
– because it’s what I’m testing here.There are very few situations where you’d want to test in this way. Initializers have no output. Perhaps it’d be useful to detail why you need to test like this? I have done it, but not to test the initializer, instead to setup an object whose initialize method had been made private.
@Nando Vieira
I have to agree your counter examples look good, but it’s still for simple example code, and lets agree, we break encapsulation in tests all the time … I know you can avoid that, but it’s like with this old databases saying “Normalize until it hurts, denormalize until it works.”
@Michal Papis
It makes no sense calling a private method (
TestMe#initialize
) to test something that you can do without breaking encapsulation.@Nando Vieira
Can you elaborate on why not? any documentation/examples why my example would be wrong/bad? For me it looks cleaner, you see the method that is tested.
Please, don’t. Just assert the behavior of your initialize method. Instead of doing what you suggested, just do something like
TestMe.new.value.must_equal nil
andTestMe.new(3).value.must_equal 3
.