About two months ago, I started a new project which heavily depends on World of Warcraft Armory data.
I found Wowr, a great ruby library which allows me to avoid the fetching and parsing of these informations, and started to use it (and contribute).
As my first version of Wowgossips is near finished, I started to run rcov on it to have a robust test suite for the future. I haven’t wrote a lot of tests during the development, and got a coverage of 60%. I started to write missings tests, and arrived to a 85% coverage. And that is here that the main problem comes : how can I test my data fetching algorythm, as it heavily uses a library (Wowr), which in turn uses an external data source (WoW Armory).
After some googling, I found a way to achieve this, using two very useful testing tool : Fakeweb and Mocha.
Mocha is a Ruby mock library, allowing you to “override” some methods with values of you choice. I use it to force Wowr to returns values I expect in my tests, without the need to fetch and parse a huge XML file from the Armory.
Before that, I started writing some XMLs, based on the Armory’s original, but with the change i wanted to test (change the character level, …). It quickly started to be unmaintenable, and pretty ugly. Now, I have a basic XML file, and I can override the Wowr method i want to test. The main problem with this approach it that is still uses an HTTP request to the Armory. As Blizzard blocks your IP address it you hit too much their servers, I was quickly limited by the number of tests I can run. And there comes Fakeweb.
Fakeweb can disable web requests made by your application (or libraries used in your code), and, like Mocha, returns a spacific string of file in place of the remote document. I installed it, configured it to return static XML files stored in my fixtures directory. Now, when I write a test involving Wowr, I add a mock on the Wowr methods involved and thats done. When I run the test, my XML fixture file is loaded, Wowr parses it, and methods I want to use always returns what I want.
A quick example :
# Setup a fake character
def fake_character character_name
character = characters(character_name)
# Force last modified date to today
character.armory_character.strubs(:last_modified).returns(Date.today)
return character
end
test "that we detects a level change" do
character = fake_character :voreen
# Overide the level returned by Wowr
character.wowr_character.stubs(:level).returns(80)
character.wowr_to_db
assert_equal 80, character.level
end
That is a clean, fast, and very flexible way to test your code if you depend on external services and/or libraries.
Tags fakeweb, mocha, rails, ruby, testing