Mocking Facebook
December 10th, 2007
Any sort of interaction with external services is a serious hassle when trying to do TDD or even Development with Some Tests In It. External services could include anything from web services like facebook to our own drb ferret service (the real purists would include your database in this, but one step at a time…). The worst thing to do is to actually interact with the service in the test—it makes tests slow, dependent on a network connection, potentially messes up production data, etc.
The solution is mock objects. For a long time I did mock objects the wrong way, by inheriting from the real object and essentially reimplementing the functionality. This is pretty painful, so I didn’t do it much. Fortunately, really good mocking frameworks are everywhere now. Ruby even has two of them—mocha and flexmock.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
def test_facebook_publish_complete_goal
@mock_fbsession = valid_facebook_session
person = people(:rob_cooper)
person.facebook_session = @mock_fbsession
@mock_team_member = flexmock
@mock_team_member.should_receive("goal.name").and_return("write a facebook app")
@mock_team_member.should_receive("goal_is_complete?").and_return(true)
@mock_team_member.should_receive("give_up?").and_return(false)
@mock_fbsession.should_receive(:feed_publishActionOfUser).
with(:title => 'has completed the goal: write a facebook app').once
person.facebook_publish_goal_activity(@mock_team_member)
end
|
First some preliminaries
First I need to set up a mock FacebookSession (I use a pseudomock wrapped around a real FacebookWebSession because I’m lazy and don’t want to mock the session_id and session_key accessors). The RFacebook library obviously wasn’t implemented TDD, so there are a few ways that it’s a bit messy to test.
1 2 3 4 5 6 7 8 |
def valid_facebook_session
mock_session = flexmock(RFacebook::FacebookWebSession.new("test", "test"))
mock_session.should_receive(:is_valid?).and_return(true)
mock_session.should_receive(:is_ready?).and_return(true)
return mock_session
end
|
1 2 |
@mock_team_member.should_receive("goal.name").and_return("write a facebook app")
|
This call is actually making a chain of mock objects, so I can call @mock_team_member.goal.name without having to explicitly create a mock object for the goal.
Here’s the guts
The first line sets up the expectation—kind of like an assert.
1 2 3 4 5 |
@mock_fbsession.should_receive(:feed_publishActionOfUser).
with(:title => 'has completed the goal: write a facebook app').once
person.facebook_publish_goal_activity(@mock_team_member)
|
The second line calls the method we wants to test. The expectation (that the method feed_publishActionOfUser will be called once with the specified arguments) will magically be evaluated when the test is over.
2 Responses to “Mocking Facebook”
Sorry, comments are closed for this article.
December 18th, 2007 at 09:28 AM Thanks for such an useful article! One thing i would like to know is if you have already done some work about developing an app using BDD with rSpec and rFacebook. I have some problems in testing stuff related to rfacebook. Thanks in advance!
December 19th, 2007 at 05:42 PM Vitor, I haven't tried using rfacebook with rSpec. I just came across a new ruby/facebook user group which might be a good place to ask: http://groups.google.com/group/rfacebook