No Internet Means Better Test Isolation


One day I found myself riding in a car with my family and it was a long road trip, with little to no internet and realized that my tests required internet connectivity. I was also heavily dependent upon code examples that I could find.

I’ve been absolutely horrible with testing my code. I would write code, test it out in the ruby console and then push it live. It felt like I was moving fast. I was being agile. Wrong! Testing is necessary in order to succeed. Often I would push code and do the good ole’ cowboy code em’ up. This is a horrible idea, don’t do that.

Stubs And Mocks

I’ve seen arguments for and against the use of stubs and mocks. I like mocks and stubs. I do think they are useful, and they have their place. Many people find themselves over stubbing and over mocking. This can lead to brittle tests.

I suppose it is tempting, if the only tool you have is a hammer, to treat everything as if it were a nail. Abraham H. Maslow

Corey Haines has a good presentation called Yay Mocks!. Definitely worth the time to watch.

Using stubs and mocks in a restrained fashion will result in maximum payoff. I attempted to stub and mock everything in a controller unit test. This turned out to be a hellish nightmare to maintain. I did discover some cool logical control flow that I could utilize. I could force CanCan to raise exceptions and cause some fun errors in the controller.

# spec/controllers/threads_controller.rb
describe ThreadsController do

  describe '#create' do
    context 'when a user is signed in' do
      before { sign_in user }
      context 'and is authorized' do
        before { controller.stub(:authorize!).and_return(true) }
        context 'and the thread is created' do
          before do
            post :create, thread: {title: 'Some Title'}
          end
          it { should respond_with 302 }
          it { should set_the_flash[:success] }
          it 'should create the thread' do
            expect(Thread.count).to eq(1)
          end
        end

        context 'and the thread is not created' do
          before do
            Thread.any_instance.stub(:valid?).and_return(false)
            post :create, thread: {title: 'Some Title'}
          end
          it { should respond_with 200 }
          it { should set_the_flash[:error] }
          it 'should not create a thread' do
            expect(Thread.count).to eq(0)
          end
        end
      end

      context 'and is not authorized' do
        before do
          controller.stub(:authorize!).and_raise(CanCan::AccessDenied)
          post :create, thread: {title: 'Some Title'}
        end
        it { should respond_with 403 }
        it { should set_the_flash[:error] }
        it 'should not create a thread' do
          expect(Thread.count).to eq(0)
        end
      end
    end

    context 'when a user is not signed in' do
      before { post :create, thread: {title: 'Some Title'} }
      it { should respond_with 403 }
    end
  end

end

Testing permissions should not apply to controller tests. This ia a boundary and should be stubbed. You can unit test your permissions in another set of tests, but they do not belong in the controller test.

Boundaries

I strongly urge you to watch Boundaries by Gary Bernhardt. Understanding where an object’s boundaries lie, is key for test isolation. Ruby has a nice open class principle that allows for stubing and mocking. Earlier I pointed out that in a controller permissions were considered a boundary.

No Internet

Now for the fun story. I had no internet on my laptop while we traveled down the highway. I was writing code and then realized I should run my tests real quick to ensure I didn’t cause a massive problem. What I found out to my surprise is that more than half of our test suite failed, due to the need to talk to a 3rd party API. Ooops.

All I had was my phone and even then all I had was spotty coverage. I remembered seeing the two videos mentioned above, and thought to myself, “This is similar to what TDD is right?” I was right, as I went through and looked at why the tests were failing, I noticed that they were failing in places that were difficult to test. On top of the areas difficult to test, it was often over stepping boundaries.

I used my phone to look up RSpec Mocks and tried out a few examples to make sure I understood what was going on.

foo = double('User')
foo.stub(:update_attributes).and_return(true)

it 'should return true' do
  expect(foo.update_attributes({:garbage => 'in'})).to eq(true)
end

Revelation

And when the test greened up, a sudden grin appeared on my face. I realized that I could do anything. I have never once been happy about testing in Java or PHP and I couldn’t help but be really excited when I started seeing some tests come up green.

I started to stub and mock places where I was making calls to an API. Many of these tests, I simulated errors that could be encountered while interacting with the API.

I realized that there were parts of our application that were extremely difficult to isolate. This was indicative of “code smell”. I wrote some tests on how I wanted the peices to interact, then made the peices interact to make the tests green.

Being able to simulate errors from the API was a HUGE help. It allowed me to see potential errors and handle them appropriately rather than show a big ole’ 500 error page to our customer.

Resources

Here is a list of resources that I utilize all the time. In fact, they are bookmarked and I often visit them.

Stand Up Desk DIY


I have been hard at work over my birthday to now. I’ve spent the better part of 20 hours with my dad working on my new standing desk. Where I was working before was extremely cluttered and an upgrade to my life was needed.

I wasn’t able to take pictures from the initial start of the project, due to us having to do multiple things at once before Home Depot closed. However, after we settled down, I had Amanda come out and take pictures as we were working on the desk.

We built the desk using Oak tongue and groove boards. My parents finished an interior remodel of their house about two years ago. A lot of oak boards were left over and my dad suggested we use it instead of buying a new sheet of Birch.

I hate glossy polyurethane. Even a satin finish still bothers me some. For me wood isn’t supposed to be reflective. I opted for a Matte finish with a Dark Walnut stain.

Staining was probably the best feeling in the world. I was so close to being done!

After three layers of polyurethane and some serious tender love and care. I took it home with me to assemble! This table is super heavy due to all the Oak that we used.

Feels great now that I have this completed!

I Graduated


Finally! I have graduated from the University of Texas at San Antonio with a Bachelor’s degree in Computer Science. I waited for 4.5 years (9 semesters) to finally reach this point in my life. Though now I wonder what awaits me in the future.

Now I’m able to work Full Time at ZippyKid where I help build and maintain the deployment system. Ever since I started working here in January 2012, I’ve grown a lot and I have learned a TON.

Things I’ve learned:

  • Rails is not the answer to all questions
  • Venturing out of your comfort zone is great
  • Good OO design is not easy
  • There is no silver bullet
  • No one really knows what they are doing in software engineering

Organizing Delayed Jobs


I despise consuming 3rd party APIs for one reason, speed. Many of the APIs I have to consume on a daily basis, respond slower than it would take to deliver an email. But, their integration with our application is absolutely critical. They are so critical infact, that if an error should happen during any point of the commissioning, then I need to be notified and or the job needs to be reattempted at a later date.

On many occassions, I have simply split the 3rd party API object into its own Rails model that is persisted in the database with a state_machine or some sort of identifier on it that lets the application know if it is in an erroneous state.

Billing is a prime example of this:

# app/models/subscription.rb
#  Table: subscriptions
#    - user_id
#    - subscription_id
class Subscription
  belongs_to :user

  def subscribe
    # subscribe to api here
    # set subscription_id = id in api
  end

  def unsubscribe
    # unsubscribe from api here
    # invoke .destroy
  end

  def update_billing_information
    # interact with api here
  end
end

I mentioned earlier that I would use a state machine on models that interact with APIs. However, in this example, if the subscription_id is not set, then the Subscription will be in an erroneous state.

I prefer to make job classes, only because they allow for me to separate my backgrounding code, from my model code. Plus, there is the possibility that you are sticking too much data into the delayed job queue by doing User.delay.send_some_email or @user.delay.send_some_email is even worse. It will turn that ruby object into a YAML formatted object and stick it into the queue.

The following is the best way, IMO to do backgrounding with Delayed Job. Just put a few simple values in and it keeps the queue lean.

# app/jobs/subscribe_subscription.rb
class SubscribeSubscription
  def initialize id
    @id = id
  end

  def perform
    subscription = Subscription.find(@id)
    subscription.subscribe
  end

  def error job, exception
    puts "[ERROR] subscription=#{@id} message=#{exception.message}"
  end
end

I would then invoke the Delayed::Job queue by using an observer. Now this part you don’t have to necessarily put into an observer, but it makes for a cleaner model. As an aside, I store my observers in app/observers, it just makes it a little easier to organize my thoughts.

# app/observers/subscription_observer.rb
class SubscriptionObserver < ActiveRecord::Observer
  def after_create subscription
    Delayed::Job.enqueue(SubscribeSubscription.new(subscription.id))
  end
end

We would then be able to do the following:

# app/controllers/subscriptions_controller.rb
class SubscriptionsController < AuthorizedController
  # ...

  def create
    sub  = current_user.subscriptions.build(subscription_params)

    if sub.save
      # success
    else
      # booo failure
    end
  end

  # ...

  private

  def subscription_params
    params.require(:subscription).permit(:name, :more, :fields)
  end
end

We have decoupled the 3rd party interaction from the controller and put it into a background job, where it will be handled. However, in this straw man example I did not show a proper way to handle failure. If I was going to actually do this with a payment system, I would definitely notify the user that something is up and make them reattempt the sign up again.

Flying with php


I discovered the Flight micro-php framework this week. I found it because I was looking for a simple PHP 5.3+ framework that didn’t have a large amount of extra cruft. I had a project to do for my Database class at UTSA where we had to utilize an Oracle database. Not exactly my choice for databases, but we had to make do with what we were given.

It is a very sparse framework that looks very similar to Sinatra except it is even lighter. Flight provided me ways to easily extend and customize.

I used a fairly straight forward file structure:

|-assets
|-config
|-controllers
|-db
|-lib
|-models
|-views

Flight doesn’t come with a Database class. So you will have to roll your own or use an ORM or use Mike Cao’s Sparrow library. I haven’t had a chance to play with it yet, but it looks very promising. Unfortunately, it does not support Oracle, so I had to roll my own implementation, and it’s not pretty by any means.

I look forward to playing with this library some more, and hopefully building something with it soon.