Entries Tagged 'General' ↓
December 18th, 2008 — General, Rails, Ruby
I see unit testing as a way to test each possible snippet of functionality and route the code in question can take. With Ruby being such a dynamic language and allowing shortcuts to common problems, sometimes it can seem somewhat of a mystery, how to test these snippets of functionality.
Using Memoization as an example:
class MyClass
def lazy_initialized_value
@lazy_initialized_value ||= Expensive.request
end
end
There are actually 3 separate snippets of functionality that need testing here, however it is not immediately obvious from the example. Lets be slightly more verbose about what is actually happening:
class MyClass
def lazy_initialized_value
@lazy_initialized_value = Expensive.request unless @lazy_initialized_value
@lazy_initialized_value
end
end
Now it is much easier to see the 3 steps the code should take:
- Store result of expensive request in instance variable
- Leave instance variable alone when it is already set
- Return the value of the instance variable
Now we have this information, our tests become (using Mocha to mock external methods):
class Expensive; end
module Tests::MyClass
# lazy_initialized_value
# ----------------------
class LazyInitializedValueTest < Test::Unit::TestCase
def test_should_respond
assert_respond_to MyClass.new, :lazy_initialized_value
end
def test_should_store_result_of_expensive_request_in_instance_variable
instance = MyClass.new
Expensive.stubs(:request).with().returns('expensive value')
instance.lazy_initialized_value
assert_equal 'expensive value', instance.instance_variable_get('@lazy_initialized_value')
end
def test_should_return_value_of_instance_varable
instance = MyClass.new
instance.instance_variable_set '@lazy_initialized_value', 'the value'
Expensive.stubs(:request)
assert_equal 'the value', instance.lazy_initialized_value
end
def test_should_maintain_existing_instance_variable_value_when_already_set
instance = MyClass.new
instance.instance_variable_set '@lazy_initialized_value', 'existing value'
Expensive.stubs(:request)
instance.lazy_initialized_value
assert_equal 'existing value', instance.instance_variable_get('@lazy_initialized_value')
end
end
end
Now we have these tests in place, we can go back and refractor the code ’til our heart’s content using all the tricks in the book but by simplifying the problem in the first place, it gives us a solid test suite and the confidence to make changes without breaking functionality.
If you were solving this problem test-first then you wouldn’t (but more likely, shouldn’t) have written the first example until re-factoring stage anyway, however when these shortcuts become engrained in your brain, it’s all too easy to forget what they are actually doing.
So there we go, simplify the initial implementation, get a solid test suite in order, then re-factor.
| Tags: Ruby, test, testing, unit
December 4th, 2008 — General
I was happily mocking away with Mocha, then I passed a stub to a case statement at which point I was a little flummoxed.
The Ruby documentation clearly states that the ‘when’ in a ‘case’ statement uses the ‘===’ method for comparing the subject so I couldn’t work out why something like the following wasn’t working:
# Code
class A; end
def foo(instance)
case instance
when A : 'an A instance'
else 'not an A instance'
end
end
# Test
a = stub_everything
a.stubs(:===).with(A).returns(true)
assert_equal 'an A instance', foo(a)
So I had a little play around in irb and found the following:
class A; end
a = A.new
a === A #=> false
A === a #=> true
This revealed that I was actually stubbing the wrong side of the operator, I changed this to the following and voila!
# Code
class A; end
def foo(instance)
case instance
when A : 'an A instance'
else 'not an A instance'
end
end
# Test
a = stub_everything
A.stubs(:===).with(a).returns(true)
assert_equal 'an A instance', foo(a)
Looks obvious now but certainly wasn’t at the time!
| Tags: mocha, Ruby, testing, unit
December 2nd, 2008 — General
There is loads of documentation and posts on Git out there so this is more of a note to self as I keep forgetting the steps to setting up a remote repository and doing an initial ‘push’.
So, firstly setup the remote repository:
ssh git@example.com
mkdir my_project.git
cd my_project.git
git init --bare
git-update-server-info # If planning to serve via HTTP
exit
On local machine:
cd my_project
git init
git add *
git commit -m "My initial commit message"
git remote add origin git@example.com:my_project.git
git push origin master
Done!
Team members can now clone and track the remote repository using the following:
git clone git@example.com:my_project.git
cd my_project
git-track origin
Note: the ‘git-track’ command is a bash function we use to save manually editing the .git/config file (add the following to your ~/.bash_profile file as outlined by darkliquid):
function parse_git_branch {
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
}
function git-track {
CURRENT_BRANCH=$(parse_git_branch)
git-config branch.$CURRENT_BRANCH.remote $1
git-config branch.$CURRENT_BRANCH.merge refs/heads/$CURRENT_BRANCH
}
Bonus
To have your terminal prompt display what branch you are currently on in green, add the following to your ~/.bash_profile:
function parse_git_branch_and_add_brackets {
git branch --no-color 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\ \[\1\]/'
}
PS1="\h:\W \u\[\033[0;32m\]\$(parse_git_branch_and_add_brackets) \[\033[0m\]\$ "
December 1st, 2008 — General
I generally make a point of not unit testing private methods however in some circumstance I find it necessary to do so. One example of this is when a class method is to be documented in the API of a library, only for use when declaring a descendent class (the Rails validates_* macros could be private for example).
Testing of private instance methods has already been documented by Jay Fields, however testing private class methods requires a little more work:
class Class
def publicize_private_class_methods
saved_instance_methods = (class << self; private_instance_methods.sort; end)
saved_instance_methods.each { |method| public_class_method method }
yield self
ensure
saved_instance_methods.each { |method| private_class_method method }
end
end
This allows you to do the following:
class Foo
class << self
private
def foo
'bar'
end
end
end
Foo.publicize_private_class_methods do |klass|
assert_equal 'bar', klass.foo
end
The same would work for protected methods by changing all instances of the word ‘private’ with ‘protected’.
All this could probably be merged into the original method by Jay, however I will leave that as an exercise for the reader.
November 29th, 2008 — General
In the years I have been working with Rails I have generally been happy to follow the conventions that it enforces. There is one that just doesn’t sit right with me and that is the decision to store .css files in a ’stylesheets’ directory and .js files in a ‘javascripts’ directory as I prefer ‘css’ and ‘js’ directories (call me old fashioned).
Achieving this in Rails 2.2 involves changing a couple of constants. I may submit a patch with a config hook for this as it feels a little dirty changing the constants directly. Add the following lines to your environment.rb file.
ActionView::Helpers::AssetTagHelper::StylesheetAsset::DIRECTORY = 'css'.freeze
ActionView::Helpers::AssetTagHelper::JavaScriptAsset::DIRECTORY = 'js'.freeze
November 26th, 2008 — General
So, after switching from Subversion to Git approximately a month ago, how has it been?
Well, what can I say, all the hype is deserved. Git makes things like branching, merging and tagging something that I no longer have to think about.
At first I wasn’t completely sold on the idea of keeping multiple copies of entire repositories on multiple machines as I keep my Photoshop originals etc. all in the repositories and feared it would take forever for the initial checkout (clone in Git). I have actually found completely the opposite in that by having the entire repository on my development machine (whether it be my office or laptop machine), the time that I save switching branches i.e. not having to checkout another branch remotely etc. far outweighs the initial “pull” time which is in fact extremely fast.
November 11th, 2008 — General
This is a very boring post considering it’s the first in over a year but hey, I have to start somewhere.
Since upgrading to Leopard, even on clean installs, it decides to show system files such as /usr /bin /etc etc. To re-hide these files use the following:
sudo /Developer/Tools/SetFile -a V /bin
The -a means “set attributes” and the V means make in(V)isible (obviously!?). You will need developer tools installed from the Leopard disc for this to work.
Why so long since the last post?
The reason for not posting in such a long time is that I was running on a broken Typo install for ages with no time to fix it. I have now moved to Wordpress as it has grown up a little since I last used it. I will be porting the Lucid theme and adding features at some point, in the meantime the Typo version is still available as a download.
October 30th, 2007 — CSS, General, Mac / OS X
Call me a cynic, but posts like this one on the Surfin’ Safari blog worry me a little. Let me explain…
I don’t know if anyone remembers back to the days of Netscape 4 and Explorer 3.5? - It was a time of table based layouts and browser sniffing. Each browser had it’s own “feature” set and this resulted in hacks galore, for example Netscape had “Layers” but Explorer didn’t, Explorer had feature X but Netscape didn’t.
Along came Web Standards and the likes of Jeffrey Zeldman fighting for a standards based approach to web development. Over a decade on, it looks like were finally getting there as even Microsoft slowly start to get things right with IE7.
As cool as the CSS Transform stuff looks, I can’t help but thing we’re stepping right back into 1995.
What does everyone else think?
| Tags: CSS, design, webkit
March 27th, 2007 — General
It’s things like this that are making me loose faith in the human race. What must go through these peoples heads? …I don’t even want to imagine.
| Tags: bizzare, sick
March 8th, 2007 — General, Mac / OS X, Rails, SonicIQ, Subversion
SonicIQ are looking for a Junior Ruby on Rails Developer.
We are based in Bournemouth, Dorset, UK. Anyone interested in working professionally with Rails on some exciting projects please drop us your CV.