Jake Scruggs

writes ruby/wears crazy shirts

Word on the street is that Lone Star Ruby Conf was one of the best regional conferences last year, so I'm pretty excited to be presenting at the 2008 edition. It's happening Sept 4-6th in Austin, TX and speakers include: Matz, Evan Phoenix, Jim Weirich, The Rails Envy Guys, and too many other luminaries to name.

I'll be giving a talk entitled "Using Metrics to Take a Hard Look at Your Code" which is a distilation of my thinking over the past year about how to use numbers not as a hammer with which to beat people, but as a tool to improve your code.

Registration just opened up today, but space is limited so go sign up soon.

Recently I spent some time away from RSpec and I did miss it, but one thing especially liked about the testing framework I lived in for 10 months was that it had two ways to test anything you liked: One that hit the database and one that did not. We used UnitRecord to disconnect unit tests from the database (I should mention that we defined unit tests as tests that didn't hit the db and functional tests as those that did). So the vast majority of our tests didn't really need to hit the db and ran very fast. Sometimes we wanted or needed to hit the db and we did (only occasionally in model tests, more often in controller tests, and we kept logic out of the view and only tested views at the Selenium level). It was pretty cool and I'd like to thank the team who set it up before I got there.

There's been a lot of talk about whether model, view, or controller tests should hit the db but I've found that there's enough exceptions that it's worth just saying that you should try not to hit the db when possible for speed's sake and then when the test becomes 20 lines long because of all the mocking/stubbing required, go ahead and hit it. That's all well and good, but how do you disconnect the db from an RSpec example?

I, personally, have had success with NullDB. NullDB is the null object pattern applied to databases. Which is a fancy way of saying that it swallows up any call that would go to the db and returns a nil. So you mock/stub all you like, but if you forget or just don't care about a particular call then don't worry because nothing goes to the db and nil is returned (which, surprisingly, is more than enough in most situations). On the NullDB page I've linked to, the author provides a way to universally disconnect RSpec from the db, but, as I've already said, I'm a bit pragmatic when it comes to disconnection so In my spec_helper.rb I define something like this:


 1 share_as :Disconnected do
2
3 before :all do
4 ActiveRecord::Base.establish_connection(:adapter => :nulldb)
5 end
6
7 after :all do
8 ActiveRecord::Base.establish_connection(:test)
9 end
10 end

and then in any "Describe" block where I'd like to disconnect the db I do this:

1 describe User do
2 include Disconnected
3 # 'it' blocks or
4 # more describes
5 end

If I want to hit the db I just don't include Disconnected.

Now since NullDB fails silently I've heard tell of problems with it being hard to debug (although I have yet to experience these problems). Any spec/test/example that just isn't behaving properly can be exiled to the 'hit the database' area. Also I should mention that when I tried to use NullDB with Rails 1.2.6 I got a bunch of errors but it worked fine with 2.0.2. If you are looking for a more vigorous enforcement of 'don't touch the db in unit tests' then UnitRecord may be for you. I thought RSpec and UnitRecord didn't play nice, but my fellow Obtivian, Ryan Platte informs me that he's got it working. So I'm calling him out to post about disconnecting the RSpec with UnitRecord.

I've been on a few projects where I've had to mess with breadcrumbs and they tend to be much more trouble than they're worth. It all starts simply enough: put the users path through the app on the page. Which isn't too hard.

Then the bugs come.

Like: "This page is linked to from page A but it really is more of a child of page B so the breadcrumbs should show page B and not A even if they come from A"

Or: "When I come to page X from the search on the front page it should have breadcrumbs with Y and Z because that's really what it's under."

And: "Page L is listed under K but should be under M (followed a few days later by) Page L is listed under M but should be under K"

Oh, you want a hierarchy. Which is hard.

First: There's now a new job to be filled: Taxonomist. Somebody is going to have to figure out where all the pages in the app fit in some sort of tree. And this list must be maintained.

Second: There must be code that manages all this. And since there are always exceptions to the rules of hierarchy it can get quite complicated.

Third: Although your customers don't really care where the page fits in the hierarchy, everyone else in the business does. A lot. So much so that there will be many (perhaps endless) arguments about exactly where things "belong."

All this will take plenty of time that could be used doing something that, you know, your customers may actually need. I guess I really don't have too much problem with "true" breadcrumbs (aside from the fact that I never use them and they're kind of a relic from the days of "Wow the internet is so complicated people will get lost!" and they can probably be replaced with a good search box) but what I really hate is when they act as a gateway drug to hierarchy.