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.

Reply via email to