Reputation: 3132
I have written a unit tests as below.
describe Youtube::Metadata do
let(:subject) { SampleMetadata.from_text(open(url)) }
context "when url is passed" do
let(:url) { "http://www.sample.com" }
describe "It should return all values from the site" do
its(:id) { should eql "234" }
its(:url) { should eql "www.sample.com" }
end
context "Given a html file with id property" do
let(:html) { File.join(PAGES, 'youtube', 'sample1.html') }
let(:subject) { Youtube::Metadata.from_text(File.read(html)) }
it "should return unique value from id property" do
subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
end
context "Given a html file with rel:canonical property" do
let(:html) { File.join(PAGES, 'youtube', 'sample2.html') }
let(:subject) { Youtube::Metadata.from_text(File.read(html)) }
it "should return unique value from rel=canonical content property" do
subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
end
end
end
I need to refactor it so that I dont have to repeat the below statement in each and every tests cases.
let(:subject) { Youtube::Metadata.from_text(File.read(html))
I tried it with before block but it didn't work.
Actually the first context we pass url and the second set of context we pass filename. Also I am not sure whether I need to make it as a single context (which is passing file name contexts, ie. last two) and describe it.
What would be the right way to do it??
Upvotes: 0
Views: 125
Reputation: 15957
I think you're asking good questions but let's take a step back regarding testing in general. You're looking to DRY up your tests because you recognize duplicate code - great. Tests are meant to be easy to read and easy to follow.
Thankfully rspec
gives you access to things like context
and describe
in order for you to separate your tests into parts. Your tests are heavily separated and you're using let variables (which in turn create instance variable scopes) for things you're only using in a single test.
To me that seems overkill and you're adding complexity to a test that is otherwise self contained in a normal it
block.
For instance, this seems like a more structured set of tests:
describe Youtube::Metadata do
include Helpers
# ... omitted ...
context "Given a html file with id property" do
it "should return unique value from id property" do
subject = file_loader('youtube','sample1.html')
subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
end
context "Given a html file with rel:canonical property" do
it "should return unique value from rel=canonical content property" do
subject = file_loader('youtube','sample2.html')
subject.unique_id.should eql "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
end
end
end
Then just create a helper like so:
module Helpers
def file_loader(dir, filename)
file = File.join(PAGES, dir, filename)
Youtube::Metadata.from_test(file)
end
end
Upvotes: 2
Reputation: 37409
You can use shared_examples
:
shared_examples_for "unique id parser" do |sample_file, expected_id|
let(:html) { File.join(PAGES, 'youtube', sample_file) }
subject { Youtube::Metadata.from_text(File.read(html)) }
it "parses unique id property" do
expect(subject.unique_id).to eql expected_id
end
end
context "Given a html file with id property" do
it_behaves_like "unique id parser", 'sample1.html', "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
context "Given a html file with rel:canonical property" do
it_behaves_like "unique id parser", 'sample2.html', "65155c6e-ba11-42fc-bb91-53520176d2a8"
end
Upvotes: 1
Reputation: 114138
Group it with another context:
describe Youtube::Metadata do
# ...
context "given a html file" do
subject { Youtube::Metadata.from_text(File.read(file)) }
context "with id property" do
let(:file) { File.join(PAGES, 'youtube', 'sample1.html') }
it "should return unique value from id property" do
# ...
end
end
context "with rel:canonical property" do
let(:file) { File.join(PAGES, 'youtube', 'sample2.html') }
it "should return unique value from rel=canonical content property" do
# ...
end
end
end
end
Upvotes: 0
Reputation: 57
First, use another name for the second and third ":subject" because you already has one in the outter block.
Second, you really need 'sample1.html' and 'sample2.html'? If not, change to 'sample.html' and move both 'let's up.
Third, check if you had some problem with lazzy load (change let to let!)
Upvotes: 0