I'm a RoR developer and recently was working on implementing an image manipulation feature in our app. I've gotten into the habit of TDD and naturally I started out by developing tests for my new class that'll handle the features.

This is what my test looked like in spec/lib/image_publisher_spec.rb

require "spec_helper"

describe ImagePublisher do

  let(:ip) { ImagePublisher.new }

  describe "#validate" do
    #...
  end
  #...
end

and I put the actual library in lib/image_publisher.rb

class ImagePublisher
  attr_accessor #...

  def initialize
      #...
  end

  def validate(path)
    #...
  end
end

After developing some tests and implementing the features I had rspec spec/lib/image_publisher_spec.rb passing. Confident in my abilities, I ran the whole suite with rspec and was met with the first shocker of the day. My new test was passing fine but another feature spec I had written earlier was failing at the before (:each) level with the error:

ActionController::RoutingError:
      uninitialized constant AdminDashboardController

To clarify, I'm using Active Admin (which incidentally hasn't been my staunchest ally in my conversion to Rails 4) and spec which started failing suddenly was this:

    #spec/features/publish_flow_spec.rb
require "spec_helper"

feature "Publish Flow" do

  let(:admin_user) { FactoryGirl.create(:admin_user) }

  before(:each) do
    sign_in_user admin_user
  end

  def sign_in_user(user)
    visit root_path
    fill_in 'admin_user_email', with: user.email
    fill_in 'admin_user_password', with: user.password
    click_button 'Login'
  end

  describe "some feature" do
      it "does something" do
          #...
      end
  end
end

The failure point was the line visit root_path and it appears the runtime couldn't find Admin::DashboardController as it seemed to be interpreting it as AdminDashboardController. What was weird was that running rspec spec/features/publish_flow_spec.rb didn't produce any errors and passed like it did before.

Quickly googling the error, I found many users facing the same dilemma and I tried the fixes they offered one by one. Here's my account.

Trying Fix #1

My gem file looked something like this.

source 'https://rubygems.org'
ruby "2.0.0"

gem 'rails', '4.0.0'

gem 'pg'

    #...
gem 'activeadmin', :github => 'gregbell/active_admin'
    #...

and the routes like this

MyApp::Application.routes.draw do
  root :to => 'admin/dashboard#index'
  devise_for :admin_users, ActiveAdmin::Devise.config
  ActiveAdmin.routes(self)
end

I moved the root definition above ActiveAdmin's definition but that didn't help. I even tried specifying my name space by config.default_namespace = :admin even though I was using the default namespace already, but it still didn't stop the old spec from failing.

Trying Fix #2

It seemed it may be an active admin issue, and I tried the fix specified in a related github issue. Sadly, specifying config.cache_classes = true in my application.rb didn't resolve the failing test either.

Trying Fix #3, #4, #5....

At this point I'd played around with enabling and disabling various permutations of config variables in application.rb, test.rb & active_admin.rb and after spending a couple of hours, nothing seemed to work. I just couldn't understand why the test would fail when run with the whole suite and not when run independently.

I even tried specifying different routes (which were valid because I could see them at http://localhost:3000/rails/info/routes) in the sign_in_user function but they all failed with routing errors.

I also thought maybe the test db was at fault but running rake db:test:prepare didn't solve anything.

Trying Fix #4

I decided to go back to a working commit which had passed all the tests before I added my new class. Here, the test seemed to work fine when run as a whole. I figured it had something to do with the ImagePublisher class I had recently created. I moved back to the most recent commit and removed rspec spec/lib/image_publisher_spec.rb and VOILA, the whole suite is passing again.

What fixed it?

Now I knew that something was wrong with the new test that I had written but couldn't figure out how it was meddling with a completely unrelated test. I decided to go back to the basics and searched for a tutorial on how to write spec tests for a class in the lib folder.

An example listed at this site gave this example:

require 'spec_helper'

describe "Library object" do

    before :all do
        lib_obj = [
            Book.new("JavaScript: The Good Parts", "Douglas Crockford", :development),
            Book.new("Designing with Web Standards", "Jeffrey Zeldman", :design),
            Book.new("Don't Make me Think", "Steve Krug", :usability),
            Book.new("JavaScript Patterns", "Stoyan Stefanov", :development),
            Book.new("Responsive Web Design", "Ethan Marcotte", :design)
        ]
        File.open "books.yml", "w" do |f|
            f.write YAML::dump lib_obj
        end
    end

    before :each do
        @lib = Library.new "books.yml"
    end

end

Hmmm...I don't know what I'm doing different but all I see is that the main describe block name as encapsulated in quotes. So that's what I decided to do:

Diff
-describe ImagePublisher do
+describe "ImagePublisher" do

Ran rspec and ALL THE TESTS PASSED!!!

Now, I have no clue why rspec was passing the classes' test and failing an unrelated test just because a describe block was named how it should be named. I had other tests named similarly for files in spec/lib, but the only difference there was that they were inside module folders and named with the namespace of that module, while this test wasn't.

Anyhoo, this weird test fixed my woes, but I'd be glad if someone can tell me what I was doing wrong in the first place by not putting the describe block title in quotes. OR, you can tell me where I can find Occam so I can kill him. Till then, I'll chalk this one up as cosmic karma.

 

Update: I figured out why all this happened. In the ImagePublisher class, I had extended the string class by doing a "Class String" instead of "String.class_eval", which basically FUBARed any other string functions elsewhere.