I am using Rspec to test a module that has an external dependency with the
Internet.
This is why I am trying to mock out the class that handles the actual
access of the webpage when running my tests.
My class "Snapshot" (that I want to test) accesses a webpage when it is
requested and will save the html in a file when the hash of the content has
changed.
The filename should have a certain name according to the date/time and a
running number.
And there should be a log message when an error occours (e.g. no Internet
or website down), containing the status code (e.g. 404).
I made some basic tests, but now wanted to write a test integrating a
couple of classes.
The only thing that I would like to mock is the Internet part.
As the snapshots are only generated when the html content changes I thought
about the following approach:
- Use timecop to fake a time and be able to check if the saved filename
corresponds to this date/time
- Mock the class "Internet" by specifying certain time spans in which the
class should return a certain content
My class under test looks like this:
class Snapshot < ActiveRecord::Base
def self.grab_website(uri)
response, content = Internet.access_webpage(uri)
# code that calculates the hash, saves the content or generates an
error log messages
end
end
My Rspec "preparation code" for mocking the class Internet looks like
this:
stub_const("Internet::WEBSITE_REPLIES", \
{ "http://www.thiswebsiteisimportanttome.com" => \
[["2015-06-12 15:30", "website_Version_A.html"] ,\
["2015-06-14 18:00", "website_Version_B.html"] ,\
["2015-06-14 18:50", 404] ,\
["2015-06-14 19:00", "website_Version_C.html"] ,\
["2015-06-26 11:35", "website_Version_D.html"]] } )
allow(Internet).to receive(:access_webpage) do |uri|
time = Time.now
content = nil
response_code = 0 # We're not connected to the internet
if Internet::WEBSITE_REPLIES.has_key?(uri)
filename = nil
timetable = Internet::WEBSITE_REPLIES[uri]
timetable.each do |timepoint_situation|
timepoint = Time.parse(timepoint_situation[0])
if time > timepoint
filename = timepoint_situation[1]
end
end
if (filename.nil?)
response_code = 0
elsif (filename.kind_of? Integer)
response_code = filename
else # filename is really a filename
content = File.read(filename)
response_code = 200
end
end
next response_code, content
end
And my actual test looks like this:
first_time = Time.local(2015, 6, 12, 15, 35)
second_time = Time.local(2015, 6, 14, 17, 00)
third_time = Time.local(2015, 6, 14, 18, 05)
uri = "http://www.thiswebsiteisimportanttome.com"
Timecop.freeze(first_time) # Version A
Snapshot.grab_website(uri)
Timecop.freeze(second_time) # Version A (no changes)
Snapshot.grab_website(uri)
Timecop.freeze(third_time) # Version B
Snapshot.grab_website(uri)
snapshots = Snapshot.all
expect(snapshots.size).to eq(2)
snapshot = snapshots[0]
expect(snapshot.time).to eq(first_time)
expect(snapshot.hash).to eq("234092384EF")
expect(snapshot.filename).to eq(...)
snapshot = snapshots[1]
expect(snapshot.time).to eq(third_time)
expect(snapshot.hash).to eq("A8E92340213")
expect(snapshot.filename).to eq(...)
# work to do: check the log messages ...
I have the feeling that there should be an easier way to do this.
Especially because I can't imagine that I'm the only one that wants to test
time dependent Website content.
I am grateful for any suggestions!
J.
--
You received this message because you are subscribed to the Google Groups
"rspec" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/rspec/c1ed74fa-8f54-40ae-a6ba-ccfab2584bc1%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.