Mocking Controller Methods for Rails Integration Testing

Ruby on Rails has some excellent test infrastructure, and integration testing is among its slicker components.

However, my own experience suggests that OpenID can show some problems in Rails’ ability to test controllers with mocking (a la Mocha).

If you use ruby-openid and open_id_authentication, as does the multi-OpenID per user test app I mentioned earlier, you don’t want to test OpenID logins for real. That would actually query an external server, which is both slower and less reliable than good tests should be.

Looking through the open_id_authentication code, it makes sense to replace the method authenticate_with_open_id() with a stub that yields appropriate parameters, automatically giving success, if called with the correct parameters.

After lots of ugly trial and error, I determined that Rails was instantiating a new controller for each request, so even if I could get hold of the appropriate controller instance it wouldn’t do me any good. I seriously considered monkeypatching the code for Rails integration test instances to add a hook that let me mock the controller — Mocha will easily produce the kind of stub function this wants, it’s just hard to get hold of the instance to add it.

Eventually, I just gave up and changed the class itself, SessionsController, to add the new stub version of authenticate_with_open_id. You can restore it afterward (I do below) so it shouldn’t cause you problems in later testing. It would be easy to abstract this into a function that took a block parameter, and only changed SessionsController for the code within that block. I won’t do that here, but it’s a straightforward addition.

Without further ado, here’s the (ugly) code I used:

class RegisterTest < ActionController::IntegrationTest
  def test_new_openid_account
    user = users(:jwz)
    session = new_session_as(:jwz)

    SessionsController.class_eval <<END_OF_EVAL
      alias :old_authenticate_with_open_id :authenticate_with_open_id

      def authenticate_with_open_id(*args)

        # Faked 'success' object
        result = Object.new()
        result.instance_eval {
          def successful?
            true
          end
        }

        registration = { :login => "#{user.login}", :email => "#{user.email}" }

        yield [result, "#{user.user_openids.first.openid_url}", registration]
      end
END_OF_EVAL

    session.openid_login_as(:jwz)

    SessionsController.class_eval {
      alias :authenticate_with_open_id :old_authenticate_with_open_id
    }

  end
end

module TestMixin
  # Caution: stub before using this method or otherwise make sure that
  # OpenID will succeed without further interaction...
  def openid_login_as(person, redir_to = "home/index")
    person = users(person)
    post sessions_path, :which_service => "openid",
        :service_login => person.user_openids.first.openid_url

    assert_select "div#flash_error", :count => 0

    assert_response :redirect
    follow_redirect!
    assert_template redir_to
  end

  def new_session
    open_session do |session|
      session.extend(TestMixin)
      yield session if block_given?
    end
  end

  def new_session_as(person)
    new_session do |session|
      session.get_login_page
      session.log_in_as(person)
      yield session if block_given?
    end
  end
end

Note that there’s a little more code that strictly necessary because I’ve used a little DSL testing language, rather like Jamis Buck’s post on integration testing above. The big class_eval with inlined strings is more than a bit messy, but it works for me. May you also have good luck with it.



Ruby on Rails Bug - directories and partials

I found a random Ruby on Rails (version 2.1, MacOS X 10.4, but I imagine it’s been there awhile on all platforms) bug today. In hopes of making Google just slightly more all-knowing, I shall record it here for posterity.

If you’re using a partial to render a chunk of a page, and you use *another* partial from that, it works fine. That’s not the bug. But say you have nested partials in your “views/users/” directory called _partial1.html.erb and _partial2.html.erb, where partial1 calls partial2. If you invoke the first partial from another view, say views/home/index.html.erb, as <%= render_partial('/users/_partial1', obj) %>, you may find that partial2 can’t be found.

Specifically, if you render partial2 from partial1 in the obvious way, as “<%= render_partial('partial2', obj.subpart) %>“, partial2 won’t be found. Partial2 will be searched for in the directory of the view that partial1 is called from, /home, not the directory where partial1 is found, /users. So if you nest partials like that, make sure to give them an explicit leading directory instead of letting Rails find them for you. Otherwise, whatever partial calls them can’t be called with an explicit directory.

I call this a bug because it significantly decreases the utility of Rails finding your partials for you in the current view, and I can’t imagine a real-life case where the current functionality is the right answer. It’s possible I just don’t fully understand the issues involved.



Compiling Ruby 1.8.7 on a PowerBook G4 with Mac OS X 10.4

I downloaded Ruby 1.8.7, patchlevel 22. Seemed like a good idea at the time. Configured, did a make, waited a bit… Boom.

No, not “boom” like “it works”. “Boom” like “it really doesn’t work.” It appears that:

  • Newer versions of the readline library prepend an “rl_” in front of function names
  • Newer versions of the readline library obsolete the old rl-less functions
  • Ruby is equipped to deal with both, using constants in its ‘configure’ setup
  • Ruby doesn’t correctly determine whether my mac has the leading “rl_” or not

The error messages I get look like this:

gcc -I. -I../.. -I../../. -I../.././ext/readline -DHAVE_READLINE_READLINE_H -DHAVE_READLINE_HISTORY_H -DHAVE_RL_DEPREP_TERM_FUNCTION -DHAVE_RL_COMPLETION_APPEND_CHARACTER -DHAVE_RL_BASIC_WORD_BREAK_CHARACTERS -DHAVE_RL_COMPLETER_WORD_BREAK_CHARACTERS -DHAVE_RL_BASIC_QUOTE_CHARACTERS -DHAVE_RL_COMPLETER_QUOTE_CHARACTERS -DHAVE_RL_FILENAME_QUOTE_CHARACTERS -DHAVE_RL_ATTEMPTED_COMPLETION_OVER -DHAVE_RL_LIBRARY_VERSION -DHAVE_RL_EVENT_HOOK  -D_XOPEN_SOURCE -D_DARWIN_C_SOURCE   -fno-common -g -O2 -pipe -fno-common   -c readline.c
readline.c: In function 'filename_completion_proc_call':
readline.c:703: error: 'filename_completion_function' undeclared (first use in this function)
readline.c:703: error: (Each undeclared identifier is reported only once
readline.c:703: error: for each function it appears in.)
readline.c:703: warning: assignment makes pointer from integer without a cast
readline.c: In function 'username_completion_proc_call':
readline.c:730: error: 'username_completion_function' undeclared (first use in this function)
readline.c:730: warning: assignment makes pointer from integer without a cast
make[1]: *** [readline.o] Error 1

To fix this, I went into the config.h file generated by configure and added some lines:

#define HAVE_RL_FILENAME_COMPLETION_FUNCTION 1
#define HAVE_RL_USERNAME_COMPLETION_FUNCTION 1
#define HAVE_RL_COMPLETION_MATCHES 1

Once I fixed that, everything worked fine, the tests passed, and ruby was ready to go.



Fink bug with Ruby and Rubygems

I’m having several problems on my old PowerBook G4 (pre-intel) running Mac OS X 10.4. I install most of my programming gadgets with Fink, a lovely program that has a vast number of useful ports in it. Unfortunately, it does *not* get along perfectly with Ruby or RubyGems.

Your gems will disappear after a “gem update –system” command. This is because Fink’s default idea of where gems should be stored is different from the rubygems default. The update occurs, gems changes that location… Boom, all your old installed gems are invisible because they’re in the wrong directory. Not so good.

Worse yet, I’ve found the fink-installed gems binary will sometimes randomly get bus errors when installing gems or documentation. *Really* not good. Installing my own rubygems from source seems to fix this problem.

Unrelatedly, I’ve repeatedly encountered the error message “ld: flag: -undefined dynamic_lookup can’t be used with MACOSX_DEPLOYMENT_TARGET: 10.1″. In fact, I get it every time I try to build a gem with any native extensions such as mysql or ruby-debug. Also not good. It looks like I can get around this by compiling my own copy of ruby — just installing a locally-sourced gems doesn’t fix this problem.

It’s annoying to have a perfectly good packaging system (fink) that I can’t use because it’s poorly integrated with ruby stuff.

On the plus side, this is exactly what I’ll need to do when deploying ruby on production boxes because the Ubuntu package system doesn’t play perfectly with ruby or gems either. So I should get used to it. And since there’s recently been that security advisory on the version of Ruby that Fink has, maybe it’s time to rebuild a recent patchlevel anyway.

I was sort of curious about Ruby 1.9… I’ll be most of my stuff doesn’t run with it yet.



OpenID Authentication in Rails 2.1

Awhile back, Dr. Nic Williams wrote about allowing multiple OpenIDs per user in your Rails apps, and even put forward a nice little Rails example app on that topic. For Rails 2.0.2, several things broke with OpenID, and the fellow at myutil.com adapted the app to Rails 2.0.2 and OpenID 2.0.2 via appropriate patching.

I downloaded myutil.com’s version of the code, made a new Rails app, and then followed their method. Specifically, I:

  • Made a new Rails app
  • Copied over their app code, including the app directory’s contents, config/routes.rb, the test directory and so on
  • Installed the appropriate Rails plugins — restful_authentication, open_id_authentication
  • Installed the appropriate gems locally - mocha and ruby-openid
  • Used GemsOnRails to freeze in the ruby-openid gem
  • Deleted public/index.html so that the default route would work as expected
  • Started up the server and went to appropriate URLs

It all worked great. I was very surprised how painless the whole thing was. I also verified experimentally that for Rails 2.0 and the current version of open_id_authentication and restful_authentication, you don’t need the extra patching that myutil.com describes. That patch has been rolled into the main distribution, and seems to work fine.

As far as freezing the ruby-openid gem instead of installing it… I don’t know why, but you can’t just install on the same system, at least on my little G4 PowerBook with mostly Fink-installed stuff and manually-compiled RubyGems. Perhaps your system is different? I didn’t have to freeze in mocha, I just installed it locally.

If you follow the same steps I did, be sure to apply the security patches mentioned at the end of the myutil.com article — could save you some trouble later. Also, there are definitely bugs in Dr. Nic’s app (example: try setting the password while there’s an OpenID attached to your login name — won’t let you log in; remove the last OpenID attached to the account and now there’s no way to log in at all)… So I recommend the code as a jumping-off point, not a finished, polished final product. Still, good work and good code all around. It’s a fine example of how to get started, and it compiled and ran very painlessly.

[Edit: the code actually ships with user “quentin” as a test fixture. Quentin’s data has both an activation code (meaning activation is pending) and an activated_at (meaning activation has finished). This minor bug still managed to bite me, so you may want to change this. You could fix it by changing the “activated?” function to use the activated_at field rather than the activation_code field, or you could just turn “quentin” into two separate users, one activated and one not.]



Unions and Computer Programming

In Paul Graham’s An Alternative Theory of Unions, he puts forward the idea that big factories were the glamorous computer companies of their day — making money hand over fist, and in need of building up very quickly to compete with each other. High-paying union factory jobs were essentially the equivalent of web designers making $300/hour during the dot-com boom. It was easier for the companies to overpay for labor and lose a bit of profit than to find talent at more sustainable prices but slow down their business growth to do it.

That idea appeals intuitively to me, and perhaps explains why we’re not seeing more unionization in the profession of software engineering. While many software engineers could use union-style protections for employment (mandatory unpaid overtime, anyone?), that’s not really why unions form. Unions are more for price-gouging the companies making the big bucks and giving a bigger slice of the profit to the employees, in return for keeping growth strong. Software engineers, while they certainly do that, don’t need collective bargaining to do it — we price-gouge pretty well individually, because we’re not required to all be paid the same thing at the same level.

If more companies had tight salary bands by the engineer’s number of years of experience — in other words, if more companies paid factory-style instead of negotiating very individually — you’d be far more likely to see unionization, because collective bargaining over salary would become necessary for the price-gouging to keep up.

Similarly, if the software industry were to suddenly dry up, or at least become a boring industry where profit levels were low and predictable (I don’t see it happening), unionization would become unlikely because there would be very little spare profit to split, and paying union wages would become prohibitive for those shops that did so. Rather like the current situation with unions — despite harsh working conditions, and in many ways more reasons for collective bargaining than ever, union membership is down. There’s just not that big a profit pie to take a slice of, and in the end, that’s a lot of what holds people’s interest in keeping the unions going.

I have no idea whether unions in computer programming would be a good thing for the programmers involved (my intuition says “no”), but it looks like market conditions will keep that from happening regardless of how I feel about it. Fair enough.



What’s Good About Inexperience and Bad Tools

Recently, I wrote about how YAGNI is an experienced programmer’s problem, and how beginning programmers, and programmers of less-advanced languages, are often much better than more advanced users at actually finishing projects. I suggested that beginning programmers’ attitude and tools might have something to do with this. What?

Well, the Agile programming folks sing the praises constantly of doing small iterations, build a little, test a little, repeat. What if they’re right?

In general, a beginning programmer is poking around and checking after each small change because they’re afraid, syntactically, that it just won’t work. They may also be caught up in the sheer wonder of it or something, but they’re also paranoid about having just made a mistake. That means they turn around and test their change immediately. In an industry where many of our serious flaws boil down to arrogance (YAGNI, premature optimization, Second-System Effect, just-sit-down-and-code, Big Design Up Front), perhaps what we need is the belief that we need to check our work constantly because something could go wrong? I can imagine less likely scenarios…

So how would beginner tools help? The answer, I believe, is that lack of tools can help. Specifically, using an editor that feels claustrophic, a debugger that we barely understand, a programming environment that gives mysterious errors which we may not be able to intuit anything about… All of these things sap our confidence more than our productivity. They make us less productive, certainly, but they make us doubt ourselves more than that. In each case, the changes make us want to stop and check more frequently because the difficulty of figuring out two or more problems at once is prohibitive.

Beginners often deal with such tools. Experts rarely do. This kind of pain, the kind that saps our confidence is easily felt, and there is great demand for tool-builders to rectify it. We had Fortran, people came up with structured programming. We had the IBM PC, and Turbo Pascal came to our rescue. JavaScript was shipped, and eventually Firebug came to our rescue. Toolbuilders love to solve these problems, because a programmer who feels less confident will look hard for a tool to fix that problem, while one who is somewhat less productive probably won’t notice. A tool that solves such a problem first will be very popular, as long as the programmer feels more confident while using it.

And yet, perhaps the beginner with the terrible, happiness-sapping tools has an advantage he doesn’t know about. Perhaps his constant, paranoid checking will cause his code to move along in small, quick chunks. Perhaps it will constantly do something visible, and frequently do something interesting. Perhaps our timid BASIC programmer whose tools give him very little confidence will find himself shipping *something* far more often than the sophisticated Haskell-fan and Rubyist with the confidence to charge into the wild blue yonder to create the ultimate gizmo… And never get to version 1.0.



Why YAGNI is an experienced programmer’s problem

It’s been pointed out recently that when it comes to finishing projects, BASIC users make us higher-level language weenies look like slackers. I mean, Python and Ruby and Haskell and Erlang are cool and all, but if they’re so much more productive then whey isn’t there an avalanche of stuff written in them by these ultra-productive twenty-times-better programmers we hear so much about?

Here’s a possibility: those languages are used by people with a fair amount of programming experience — rarely does a new programmer start with Ruby, and essentially never with Erlang or Haskell. Even Python, for all it’s vaunted teachability, is still mostly used by people who do a lot of programming, usually after they get fed up with maintaining any large project in Perl. BASIC, as a rule, is used by people who are just figuring this stuff out. It’s why they’re still using BASIC rather than one of the many more powerful languages, for any of fifty definitions of “more powerful”. For each of those definitions, I promise you that there’s something more powerful than BASIC out there. BASIC is for beginners.

So why would beginners be better at finishing stuff than experts? That seems counterintuitive if it’s true. Before I suggest a reason, let’s think about YAGNI and the Second System Effect.

YAGNI (You Ain’t Gonna Need It) is meant as an antidote to the programmer’s constant companion, feature creep. When you tell somebody about the massive 3D graphics library you’re writing that micro-optimizes all the polygon fills according to what texturing options are selected, and you’ll get started on your game right after you get this one tricky case right… The right response to you is “YAGNI”. First, just get something running. Then you can micro-optimize, if you actually need it. First, measure and see if you do. Otherwise, YAGNI.

The Second System Effect is the buildup of cool feature ideas you had, and now that you’ve built something, it’s time to rebuild it to use all those excellent features you were totally going to add to version one if your manager/partner/schedule/self-esteem hadn’t stopped you from doing it all the first time. Brooks’ The Mythical Man-Month says to “plan to throw one away because you will anyway.” The dark, dangerous side of that advice is that after you’ve build a prototype or mock-up, you want to add all the really good features to the next version, now that you’ve, like, totally got it figured out. That’s called the Second System Effect. Beware it.

Beginning programmers, as a rule, are timid. They don’t have a good feel for what they’re doing. They’re worried about how to solve problems, and they’re pretty happy to have something simple to play around with. People willing to admit to you that they’re beginning programmers aren’t usually the ones with ridiculous, grandiose, can’t-be-finished-in-ten-years design documents. That’s people with a little experience under their belt, or perhaps beginning game designers. And you know what? Beginning programmers are often pretty good about producing something small, and then saying, “hey, I did this!”

It’s after that that you’ll start seeing people building huge, elaborate infrastructures for projects that never seem to quite get off the ground. They’re sure it’ll all work fine just as soon as they build this next big library that does this really cool thing… And then they’ll build a start menu so you can run the program and see something… At least, right after putting together the opening credits, and the graphics library to make the opening credits, like, utterly awesome.

Programmers who aren’t beginners, but aren’t old and grizzled, suffer tremendously from feature creep, the Second System Effect, lack of YAGNI-style perspective… They’re just a lot less likely to get things done. And while experienced, skilled programmers seem like they should get that figured out, it seems to take a long time. Why is there a whole body of literature on how to get programmers to build things in little pieces and make them do something useful at each step? Because programmers are really surprisingly bad at doing so. It’s hard to say if all those instruction manuals help people’s programming practice, but we can safely say that programmers aren’t just already doing everything they advise…

So why don’t beginners have the same problem? I have some theories about their development tools and how they use them… To be continued.



Tomagotchi Effect Plus Eating Your Own Dogfood

In Paul Graham’s recent post, Be Good, he mentions the “Tomagotchi Effect,” that once you have users of your product they keep complaining to be taken care of and so you keep working at it. I can vouch for this, at least in noncommercial projects. I was never more involved in Phantasmal or my DGD pages than when people were actually using them and commenting.

This effect can be harnessed for internal corporate development as well — one of the advantages of making your best programmers be tool-builders for everybody else is that everybody else will use and critique the tools. As they ask for maintenance and more features, this will keep your best programmers engaged and thinking about the tools they make, even between releases. By releasing often, you can quickly fix the problems of your internal users, thus improving the product and reinforcing the feedback. It’s a virtuous cycle.



Overtime == Bozo Syndrome

You know how you say you want a small, sharp team rather than a larger team with worse people?  Of course you do.  Everybody does.  Let’s say that you get such a team, and then they’re slightly late delivering something.

If you then ask them to work lots of overtime, what you’re doing is trading your small, sharp team for an effectively larger (more man-hours) team of stupider people.  Because you’re getting the same people, but tired and burned out.

Oddly enough, if you’re going with a consulting company you’ll pay more for that privilege, too.