Thursday, June 04, 2009

Seting Custom Headers in ActiveResource Requests

Recently had to figure out how to send a custom http header when accessing a resource through ActiveResource. Basically, you need to add the header to the connections default header hash. In your active resource class:


class ActiveResource::Connection
alias :static_default_header :default_header

def set_header(key, value)
default_header.update(key => value)
end
end

class FunkyResource < ActiveResource::Base
...
connection.set_header('SHOE_SIZE', '12')

end


Now all HTTP requests for that resource will include the HTTP header SHOE_SIZE.

Sunday, February 22, 2009

Taming Shoulda

Ok, so I've been using shoulda for the last couple of weeks, and while its certainly reduced the amount of duplicated code in my test, and given me more meaningful test descriptions, I've also noticed that its a little hard to find things with all the indented levels of contexts, setups, and shouldas. And I find that I still end up with duplicated setup and testing code. Fortunately, this is fairly easy to address by writing your own shoulds and context methods.

Custom shoulda's

Lets look first at writing your own shoulda method. Lets say you are testing a method that parses some file and returns the extracted data, along with a lit of any errors it found:

result, errors = MyClass.parse(file)

We want to test this with a number of different test files, so we end up with tests looking like this:

context "when parsing abc.tst" do
setup do
@result, @errors = MyClass.parse("abc.tst")
end
should "have no errors" do
assert @errors.empty?
end
should "have some expected result" do
....
end
end

So a number of our tests is going to be checking that @errors is empty. While its only a few lines, it does add some visual clutter, and is easy to clean up with our own shoulda method:

def self.should_have_no_errors
should "have no errors" do
assert @errors.empty?
end
end

This needs to be before your tests are defined, since it is a class method which will be executed during the loading of the class. Now, we can replace three lines with one:

context "when parsing abc.tst" do
setup do
@result, @errors = MyClass.parse("abc.tst")
end
should_have_no_errors
should "have some expected result" do
....
end
end

Our shoulda methods can also take parameters, so if we wanted to test for the presence of errors, we could add a should_have_error method:

def self.should_have_error(regex)
should "have error matching #{regex.to_s}" do
assert_match regex, @errors.first
end
end

which we would use with

should_have_error /Invalid Attribute/

Custom Contexts

The next thing we notice is that a lot of our tests are going to have similar setup sections, but we can't use a common context because the file names are different. To address this, we can create a custom context:

def self.when_parsing(filename, &block)
context "when parsing #{filename}" do
setup do
@result, @errors = MyClass.parse(filename)
end
block.bind(self).call
end

Now, our tests look like this:

when_parsing("abc.tst") do
should_have_no_errors
should "have some expected result" do
...
end
end

I find this particularly convenient for handling logins when testing rails functional tests:

def self.logged_in_as(sym, &block)
context "logged in as #{sym.to_s}" do
login_as(sym)
end
block.bind(self).call
end

logged_in_as(:quentin) do
[test normal user stuff]
end

logged_in_as(:admin) do
[test admin access]
end

Thursday, February 05, 2009

Shoulda

Recently, I've been using shoulda for improving my test code. There are a number of things I like about shoulda:
  • Unlike rspec, shoulda works with your existing tests
  • It lets you separate out common set-up and tear-down code that isn't needed for every test
  • Adds some organization to your test files, making it easier to find things
  • Allows you to describe test cases in real English, insteadOfMixedCaseIdentifiers
When I first started using shoulda, I organized my tests the same way I had in my pre-shoulda days - be method tested, so I might have:

class StackTest
context "Stack" do
setup { @stack = Stack.new }
context ".pop" do
should "Return nil if stack empty" do ...
should "Return top of stack" do...
...
end
end

However, I have come to the conclusion that a better approach is to organize by the state of the object under test, since this will allow you consolidate your setup/teardone code more effectively, and also force you to think in terms of the object rather than the individual methods:

class StackTest
context "An empty stack" do
setup { @stack = Stack.new }
should "Return nil on pop" do
should "Have one item after a push" do ...
should "return top of stack" do...
...
end
end

There are a number of other things that make shoulda tests more maintainable:
  • Don't nest contexts too deeply, as it makes it harder to find things
  • Don't just throw tests together in the same context because they happen to share some setup code - think in terms of the state of the object or class being tested
  • You can use contexts without setup to organize - like having a context for grouping together class methods
  • Write your own shoulda clauses for commonly tested conditions
  • You can make it easier to parse output into contexts/shouldas by capitalizing each description

Friday, November 28, 2008

Android Applications

So I've spent the last month writing a few of applications for the Android phone. I got a TMobile G1 a couple of months ago, and I have to say, its very neat to program for.

This means that, with a few exceptions, there will probably be very little money in writing Android applications. As we have seen with the iPhone, expect a flood of free/cheap apps drive user expectations as to what an Android app should cost. The lower barrier to entry for Android development as compared with the iPhone means that developers will flock to the platform, so there will be plenty of competition driving prices down, as well as open source efforts.

There may still be a few ways to make some decent money as an Android developer, but none are particularly easy:
  1. Make up for low price by being very popular - yeah, much easier said than done.
  2. Provide a combined web/android service that people are willing to pay a subscription for - of course, you'll still be competing with a lot of low price/free offerings, but at least you'll be getting a steady revenue stream from your users.
  3. Develop custom enterprise applications - not particularly fun, but it pays the rent
  4. Get someone else other than the user to foot the bill, advertising being the most obvious way to do this.
Still, I plan to write some more apps. For one thing, its a lot of fun. For another, I'm not impressed by very many of the Android programs I've tried out so far. More about that later.

Sunday, November 09, 2008

So I just got myself a T-Mobile G1 Android phone. I don't know how it will fare against the iPhone, which in many ways is better designed (but alas, not open source), but I'm guessing it will do well against its other competitors.

Thursday, October 23, 2008

Android

I started playing with Google's Android SDK today - long enough to implement a simple "Hello World" app. Unfortunately, between the android emulator, firefox, and NetBeans, my four-year-old laptop is struggling to keep up. While android in not as popular as the iPhone (and may never be), writing in Java has got to be better than working in Objective-C - an ugly languange from what I've seen, at least syntactically. And with android, there is at least some hope that other languages would be available - although the only success I've heard of is with scala.

Another posibility, is, of course, javascript, especially once Google ports Google Gears to Android, although the only problem there is that it won't neccessarily have acess to all the phone's features.

Monday, October 13, 2008

The consensus at Ruby DCamp this weekend was that we should be using gems rather than plugins for sharing rails code (of course, not everyone agrees. This was primarily because gems are versioned and handle dependencies automatically. This being the case, why are so many rails enhancements packaged as only plugins? Couldn't we do everything as gems?

I think a lot of people view plugins as specific to a specific rails application while gems apply to ruby as a whole. I guess a lot of people don't know how easy it is to set up a separate gem repository for your application. With plugins, you can also easily identify which plugins an application uses. A new change to rails, gem dependencies, makes this even easier, and allows you to specify what gems your application depends on, and even gives you a task to install any required gems.
 
javascript:void(0)