I am writing some rspec's to test some modules correctly implement their behaviour.
The module looks like this:
module Under::Test
def some_behaviour
end
end
I can't do this in RSpec:
describe Under::Test do
subject {Class.new{include described_class}.new}
At the point #described_class
is called, it can no longer be resolved because self is an instance of Class, which doesn't have a #describe_class method. So I am forced to repeat myself:
subject {Class.new{include Under::Test}.new}
Or use it in the spec in a different way to how it's used by my clients:
subject {Object.new.extend described_class}
This has the same end effect, but something in me thinks that if I'm asking my clients to include Under::Test
, then the tests should look as close to how it's used by them as possible.
I can use the closure property to fix this, but I wonder if it's no better. Does this have code smell?
describe Under::Test do
subject {mudule = described_class;Class.new{include mudule}.new}
it 'has some behaviour' do
expect(subject.some_behaviour).to be
end
end
Note, I also asked in r/ruby on reddit, someone there suggested:
subject {Class.new.include(described_class).new}
which might be how I go.
If your eventual aim is to include
the current described_class
module in a newly created Class
, how about the following workaround?
RSpec.describe NewModule do
let(:test_class) do
Class.new.tap do |klass|
klass.include(described_class)
end
end
specify do
expect(test_class.ancestors).to include described_class # passes
end
end
And here's an example of including the module's methods in an object:
module NewModule
def identity
itself
end
end
RSpec.describe NewModule do
let(:one) do
1.tap do |obj|
obj.class.include(described_class)
end
end
specify do
expect(one.identity).to eq 1 # passes
end
end
Note that the include
method for a Class
isn't private
in Ruby v2+. If you're using an older version, you have to use klass_name.send(:include, described_class)
I think both of your solutions are just fine, I like a little bit more
Object.new.extend described_class
for its readability and conciseness. If you want to use Class.new
approach I think it's ok to repeat module name, as Jared said, readability is more important here than dryness.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With