Closet Coder

I work in my closet. I code. Yep.

Who Is a Good Tester?

| Comments

A good software tester…

  • Constantly asks, “What is the best test I can execute right now”.
  • Can log unambiguous bugs with clear repro steps that make the main problem obvious with few words.
  • Is not distracted by their understanding of developer decisions. Just because the tester may understand certain technology constraints motivating dev solutions, the tester’s mission is never to defend the AUT see my post, What We Can Learn From Dumb Testers. It is to communicate how the AUT currently works, in areas that matter right now.

via Test This Blog - Eric Jacobson’s Software Testing Blog: Who Is A Good Tester?.

Rails Controller Specs With Users, Roles and Nested Routes

| Comments

I’ve long put off testing my controllers because of user authentication and nested controllers, dealing with stubs, etc.

But today, a fully working test!

As background, Advertisers have many trackers and the routes look like this:

config/routes.rb
1
2
3
4
5
ActionController::Routing::Routes.draw do |map|
  map.resources :advertisers do |advertisers|
    advertisers.resources :trackers
  end
end

To set everything up in the specs, I included all the files in the spec/support directory and used Mocha as my mock framework

spec/spec_helper.rb
1
2
3
4
5
Dir[File.expand_path(File.join(File.dirname(__FILE__),'support','**','*.rb'))].each {|f| require f}

Spec::Runner.configure do |config|
  config.mock_with :mocha
end

Then I set up my factories (rather than fixtures) using Factory Girl

spec/factories.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Factory.define :user do |user|
  user.sequence(:login) { |n| "username#{n}" }
  user.password 'password'
  user.password_confirmation { |u| u.password }
  user.sequence(:email) { |n| "email#{n}@example.com" }
  user.first_name "Mama"
  user.last_name "Foo"
end

Factory.define :advertiser do |advertiser|
  advertiser.name 'Advertiser 1'
end

Factory.define :tracker do |tracker|
  tracker.name 'Tracker 1'
end

Now we get down to brass tacks. In order to make my tests DRY (appropriately) and allow for all my controllers to test if someone is logged in and has access, I set up this shared context

spec/support/user_authentication.rb
1
2
3
4
5
6
describe "an admin is logged in", :shared => true do
  before(:each) do
    controller.stubs( :login_required => true)
    controller.stubs( :current_user => Factory.build(:user, :login => 'admin', :roles_list => ["super"]))
  end
end

From there, all we need to do is put it all together, setting up trackers parent @advertiser and the @tracker we’ll be using and stubbing the ActiveRecord find so that it always returns @advertiser

spec/controllers/trackers_controller.rb
1
2
3
4
5
6
7
8
9
describe TrackersController do
  it_should_behave_like "an admin is logged in"
  integrate_views

  before(:each) do
    @advertiser = Factory.create(:advertiser)
    @tracker = @advertiser.trackers.create(Factory.attributes_for(:tracker))
    Advertiser.stubs(:find => @advertiser)
  end

Now we simply specify the part of the path that is needed to find the nested route by using :advertiser_id => @advertiser

spec/controllers/trackers_controller.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  it "index action should render index template" do
    get :index, :advertiser_id => @advertiser
    response.should render_template(:index)
  end

  it "show action should render show template" do
    get :show, :advertiser_id => @advertiser, :id => @tracker
    response.should render_template(:show)
  end

  it "new action should render new template" do
    get :new, :advertiser_id => @advertiser
    response.should render_template(:new)
  end

  it "create action should render new template when model is invalid" do
    Tracker.any_instance.stubs(:valid?).returns(false)
    post :create, :advertiser_id => @advertiser
    response.should render_template(:new)
  end

  it "create action should redirect when model is valid" do
    Tracker.any_instance.stubs(:valid?).returns(true)
    post :create, :advertiser_id => @advertiser
    response.should redirect_to(advertiser_tracker_url(@advertiser, assigns[:tracker]))
  end

  it "edit action should render edit template" do
    get :edit, :advertiser_id => @advertiser, :id => @tracker
    response.should render_template(:edit)
  end

  it "update action should render edit template when model is invalid" do
    Tracker.any_instance.stubs(:valid?).returns(false)
    put :update, :advertiser_id => @advertiser, :id => @tracker
    response.should render_template(:edit)
  end

  it "update action should redirect when model is valid" do
    Tracker.any_instance.stubs(:valid?).returns(true)
    put :update, :advertiser_id => @advertiser, :id => @tracker
    response.should redirect_to(advertiser_tracker_url(@advertiser, assigns[:tracker]))
  end

  it "destroy action should destroy model and redirect to index action" do
    delete :destroy, :advertiser_id => @advertiser, :id => @tracker
    response.should redirect_to(advertiser_trackers_url(@advertiser))
    Tracker.exists?(@tracker.id).should be_false
  end
end

Works! And works great! A minimal and excellent way to test your controllers, especially for access. You can easily create additional shared contexts with different user permissions and extend out the tests to make sure users that don’t have access can properly access them.

Simplicity

| Comments

I’ve read quite a bit lately about simplifying our lives–mostly from a personal perspective, i.e. having less stuff, doing fewer things, focusing on the right things. It made me wonder how that translates to the professional level.

Apple, 37 Signals and many other companies make a living making software simple AND effective to use. That’s one way that it translates–on the macro level, but how about on the micro level? What is your absolute minimum work setup where you are free from distractions and free to do everything you need to do? Are there things that initially seem like “extras” that are actually a big deal? Are there things that you have in your workspace that you could easily do without now?

I thought about these things for my job and realized that my minimum workspace is deceptive: My MBP + my iPhone + a chair + a desk. At first it seems simple, but those first two items pack so much punch and are so high end that while they are simple, they are not as “minimalistic” as they sound as the list sounds at first. Within the iPhone I have apps upon apps that help me stay on top of things. Within my Mac, I have my workspace tuned nearly to the pixel on 6 spaces that are specifically arranged–all for efficiency and separation. But I can do 100% of my job from only these tools. Sure, a second monitor helps. Sure, a backup drive is dumb to be without for long. Sure, I like my digital picture frame–but in reality, these items are nice-to-haves–even the backup since DropBox came on the scene–not criticals.

I know several people that this list would be incomplete for. My coworker simply could not be effective without a whiteboard. Another coworker would be rendered useless without the filing cabinets she has.

What is on your list of criticals for your job?

Python vs. Ruby - a Fight to the Death

| Comments

When you’re discussing efficiency, a lot of what comes up is the details.  There is something to be said for the “beauty” of limitation and the “efficiency” of beautiful things–especially the efficiency of our brains processing it.

A talk about the Zen of Python, monkey patching (several times), the Ruby community's reckless hastiness, the syntax of RSpec and cucumber, beauty and ugliness in languages and testing tools, the complexity of the languages' grammars, syntactic vs. semantic complexity, the relative taste of grasshoppers and tree bark, etc., etc.

Python vs. Ruby: A Battle to The Death from Gary Bernhardt on Vimeo.

via Extra Cheese.

PDF Generation in Rails... The Right Way

| Comments

As long as we’re talking about efficiency here, one of the ways to be more efficient is to use the right tool for the job.  I’ve done PDF generation on 3 different projects but the PDF generation I did yesterday was by far the easiest.   What I thought would take me 2 days ended up taking about 3 hours (with research, etc).

If you’re not using Ruby to automate some part of your job or life, I feel sad for you (at least a little).   The next time you need to generate PDFs, why not try out the excellent Prawn library?  Not familiar, you say?   Well, let’s dive right in, shall we?

For those of you that used Prawn in an earlier 0.3 form, it’s recently been drastically improved and released as 0.7 in a push towards 1.0.  The APIs are very full featured (if sometimes a wee bit clunky–but PDF generation is a messy business) and simple to use. All of this is even better when integrating Prawn into Rails as a template builder using prawnto:

1
./script/plugin install git://github.com/huerlisi/prawnto.git

Even though thorny-sun originally wrote prawnto, their branch is no longer maintained, it appears.  Thank goodness for github since huerlisi seems to have picked up right where they left off.

Once we’ve got prawnto installed, there isn’t actually anything else we need to do to be ready to generate PDFs in our views. Let’s start of with something useful. A table in show.pdf.prawn:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
pdf.font 'Courier' do
  pdf.table object.line_items.collect {|li|
          [
              li.description,
              (li.quantity.nil? ? "" : "#{li.quantity}"),
              (li.rate.to_f == 0 ? "" : number_to_currency(li.rate)),
              (li.amount.to_f == 0 ? "" : number_to_currency(li.amount))
          ]
      },
      :font_size => 8,
      :vertical_padding => 2,
      :headers => ["Description", "Quantity", "Rate", "Amount"],
      :header_color => "888888",
      :header_text_color => "FFFFFF",
      :border_width => 1,
      :width => pdf.bounds.width,
      :column_widths => {0 => pdf.bounds.width-180},
      :align => {2 => :right, 3 => :right}
end

Tell me that isn’t readable? 30 seconds and you can tell exactly what that’s doing.

And we can even extract it to a partial! The only thing you have to do to make it a partial is rename the pdf object to something else, conventionally “parent_pdf”

1
2
3
4
5
6
7
parent_pdf.font 'Courier' do
  parent_pdf.table object.line_items.collect {|li|
          [
              li.description,
              (li.quantity.nil? ? "" : "#{li.quantity}"),
       ...
    # etc...

And then call the partial from show.pdf.prawn

1
render :partial => 'object', :locals => {:object => @object, :parent_pdf => pdf}

and index.pdf.prawn

1
2
3
4
5
6
first = true
@objects.each do |object|
  pdf.start_new_page unless first
  render :partial => 'object', :locals => {:object => object, :parent_pdf => pdf}
  first = false
end

And make sure our controller actions can respond to the ‘.pdf’ format.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  def show
    @object = Object.find(params[:id])
    respond_to do |format|
      format.pdf do
        send_data(render(:template => 'objects/show.pdf.prawn', :layout => false),
          :filename => "#{object.name}.pdf",
          :type => 'application/pdf',
          :disposition => 'attachment')
      end
    end
  end

  def index
    @objects = Object.all
    respond_to do |format|
      format.pdf do
        send_data(render(:template => 'objects/index.pdf.prawn', :layout => false),
          :filename => "objects.pdf",
          :type => 'application/pdf',
          :disposition => 'attachment')
      end
    end
  end

Everything is separated where it needs to be. All the view logic is in the views, model logic is in the models, and controller logic isn’t duplicated elsewhere.

Make sure and check out the various Prawn examples and do your next PDF generation right.

"I Need to Talk to You About Computers."

| Comments

Nothing is simply black or white.

Old Worlders are particularly sensitive to certain things that are simply non-issues to New Worlders. We learned about computers from the inside out. Many of us became interested in computers because they were hackable, open, and without restrictions. We worry that these New World devices are stifling the next generation of programmers. But can anyone point to evidence that that’s really happening? I don’t know about you, but I see more people carrying handheld computers than at any point in history. If even a small percentage of them are interested in “what makes this thing tick?” then we’ve got quite a few new programmers in the pipeline.

The reason I’m starting to think the Old World is ultimately doomed is because we are bracketed on both sides by the New World, and those people being born today, post-iPhone and post-iPad, will never know (and probably not care) about how things used to work. Just as nobody today cares about floppies, and nobody has to care about manual transmissions if they don’t want to.

via stevenf.com - I need to talk to you about computers. I’ve been….

The Path to Rails 3: Greenfielding New Apps With the Rails 3 Beta

| Comments

Upgrading applications is good sport and all, but everyone knows that greenfielding is where the real fun is. At least, I love greenfielding stuff a lot more than dealing with old ghetto cruft that has 1,900 test failures and 300 errors, 20,000 line controllers, and code that I’m pretty sure is actually a demon-brand of PHP.

Building a totally new app in Rails 3 is relatively simple especially if you’ve done it in previous Rails versions, but there a few changes that can trip you up. In the interest of not missing a step someone may need, this post is a simple walkthrough of building a new app with Rails 3.

via omgbloglol - The Path to Rails 3: Greenfielding new apps with the Rails 3 beta.

The Building Blocks of Ruby

| Comments

While the Python version may not be quite as pretty, nothing about them screams “Ruby has much stronger capabilities here”. Instead, by using examples like Sinatra, Rubyists trade in an argument about great semantic power for one about superficial beauty.

Rubyists, Pythonistas and others working on web development share a common language in JavaScript. When describing blocks to “outsiders” who share a common knowledge of JavaScript, we tend to point at JavaScript functions as a close analogue. Unfortunately, this only furthers the confusion.

On the Ruby side, when PHP or Java announces that they’re “adding closures”, many of us don’t stop to ask “what kind of closures?”

Let’s cut to the chase and use a better example of the utility of Ruby blocks.

via The Building Blocks of Ruby « Katz Got Your Tongue?.

iPad - the Future of Casual Computing

| Comments

I read a great article last week about the complexity and power of computers vs. what most non-Gen-X-ers want and it really got me thinking about the iPad.

The audience for the iPad is larger than the audience for the iPhone, even larger than the audience for a Mac. It’s a nearly complete computer replacement for a whole segement of the population. Some college students have the potential to get by without a computer at all. Imagine if everything fit into your $800, top-of-the-line device that you carried around under your arm. You could read your textbook, take notes, listen to music, watch movies, check e-mail… scratch that, check Facebook, browse YouTube, compose your paper, balance your budget and map out where to eat after study hall. It’s a fully functional device that is a tiny dent in their pocketbooks compared to a laptop.

Some tech-guy’s non-tech wife is going to learn to love this thing. She’s going to easily sync all of her music onto it and appease the kids during a long car ride by playing songs they like and distracting them with a kid movie that is downloaded straight to the device. She’s going to read her blogs about Twilight and Harry Potter while she’s waiting for the kids to come out to the car after class. She’s going to be bored one night and buy a few books on the iBookstore and realize how incredibly easy it is to access it. Instead of having to go to a specific website, her husband is going to install Mint on her iPad and she’s going to be able to see what their balances are at just about any time. And when she’s not using it, she’s not going to complain that it makes the house look junky, because it’s going to sit on their desk and show pictures of the latest family vacation in a beautiful slide show.

And your grandmother is going to love this. You’re going to give her the 3G version for Christmas and show her how to activate the $15/month connection whenever she needs it. She’s going to check her e-mail and see the pictures you attached. She’s going to have her calendar right there and she’s going to be thrilled with the fact that she can syndicate with your calendar and know when you’re unavailable. She’s going to be extatic about the kids pictures that she can so easily download and the little bit of web surfing she does works great on the iPad. It’s a complete computer replacement for her.

And it’s also a complete computer for small children. Imagine children’s educational apps, especially ones that take the outside edge of the device and ignore any input. Imagine kids that get a specific amount of time to watch movies and listen to their favorite music. Imagine them playing a few games as well. Do they even care about having a “real” computer? And how expensive is it? Not very expensive at all. $500 for a “kid friendly” version–a Christmas + Birthday present for a 6 or 7 year old…

And it will work great for sales, for businessmen on the go… there is a huge segement of the population that is about to get a very cheap and very high-tech computing device that they can take anywhere.

Will it replace the laptop or the desktop? Not by a long shot. Will it reduce their sales? Possibly. Will it increase adoption in general. You betcha.

An exciting place to be.