Archive for November 2006

Testing with Mock Objects in Rails

UPDATE: May 24th, 2007
This post is now woefully out of date; since it was written, several excellent mocking libraries have been released, and some testing frameworks include mocking functionality of their own. Watch the Four Labs blog for an updated version of this, coming soon!

—–

My last two posts on Ruby on Rails both dealt with using external resources in your application (Akismet and the Yahoo Term Extractor, respectively). One difficulty that often arises when code relies upon external pieces is testing - third parties often frown on the high-volume, rapid hits that a comprehensive test suite generates, and test runs can be dramatically slowed when they rely on resources outside the local machine or network. Luckily, Rails has built-in support for a technique that resolves both of these difficulties: mock objects.

The basic idea is that, for the bulk of testing, you don’t hit the remote resource itself. Instead, you define a mock version of it that responds to the appropriate calls, and (for a limited set of inputs) produces the same output that the real resource would.

An Example

The following is an example of using a mock object to test application functionality that relies on the TagExtractor class we looked at in a previous post. In the test/mocks/test folder, we created a file named tag_extractor.rb that contains the following:

require 'models/tag_extractor' 
class TagExtractor
  def self.extract(text)
    unless text.blank?
       ['tag1', 'tag2', 'tag3']
     else
       []
     end
   end
end

When you run the tests for your application, this TagExtractor class definition will override the normal one, and you’ll get an array consisting of tag1, tag2, and tag3 for any text you pass to the extract method (or an empty array, if you pass nothing). Once that’s set up, you can test the rest of your application as if the TagExtractor class were actually calling out to Yahoo.

But…

Of course, we’ve now introduced a problem into our testing - we’re no longer testing the real TagExtractor class. As things currently stand, every call to TagExtractor.extract from within the test environment will go to the mock object, so we have no way of verifying that our code to interact with the Term Extractor service is correct.

The solution to this problem is simple, and is due to the same characteristic of Ruby that makes testing with mocks so easy. Basically, if multiple definitions exist for a class (or method, etc.), the last one the interpreter finds wins. In the case above, the real TagExtractor class definition is read before the mock definition, so the mock definition is used in tests. To get the real definition back, we just need to re-insert it into the stream after the mock definition is read. So, in the unit test file for the TagExtractor class, we do:

require File.dirname(__FILE__) + '/../test_helper'
require 'models/tag_extractor' 

class TagExtractorTest < Test::Unit::TestCase
   ...
end

With that, the TagExtractor unit tests use the real definition (and call out to the real web service), while any other unit tests and functional tests that exercise the tag extractor functionality use the mock definition.

Add to Del.icio.us | Digg This | Leave a Comment

Media Temple Grid Server on Rails

Earlier this week I wrote about LiteSpeed. Besides potentially being expensive, it also requires having your own server or VPS.

Another option, great for traffic-moderate sites, is Media Temple’s Grid Server (GS). The basic set up costs $20/month and there is an option to add a 64 MB Rails container. All users appear confined to a chrooted environment, which is great because other users have no way of accessing your files, especially those hard-coded database passwords. For additional money, you can allocate more memory to the Rails container: $25/month for 256 MB and $75/month for 1 GB.

Creating a GS account is pretty fast and easy. About thirty minutes after entering my contact and billing information, I received my GS login information. The following outline describes how to deploy your Rails application.

  • Create a new domain for your account, perhaps myapp.mydomain.com.
  • Enable the Rails container in the Media Temple control panel https://accountcenter.mediatemple.net/.
  • Run mtr generate_config to avoid having to enter the user and pass everytime. This info gets stored in a ~/.mtr file in clear text, but it should be secure enough since no one else may access your home dir and it has appropriate permissions.
  • The instructions for installing the necessary files into your container are found in the MT Grid Server guide.
  • Create your database in the control panel (Manage Databases, not MySQL or PostgreSQL Admin.)
  • We have a slightly custom rake process, but perhaps the standard rake db:migrate RAILS_ENV=production will work for you.
  • The permissions of your application files must must be readable by the web server:
    # cd into the rails container
    cd $HOME/../../containers/rails/ 

    # All files should be readable
    find . -type f -exec chmod a+r {}

    # All directories should be executable and readable
    find . -type d -exec chmod a+rx {} ;
  • Don’t forget to update your production settings for the database, ActionMailer, and other deployment specific features.

After this is done, you should be able to access your application. You can manage your container from the command line using Media Temple’s mtr command. Run mtr -h for more information.

In the long run, it may be more flexible and cost-effective to go the VPS route if you have, or want to learn, the Linux side of things; but, if that isn’t your thing, the Grid Server is a good deal.

References

Add to Del.icio.us | Digg This | Leave a Comment

Get your Analytics On - Google Style

There are a significant number of web analytics packages on the market today. But, when Google entered the market about a year ago through their purchase of Urchin, they changed the face of the game by offering a relatively robust stats package at zero cost (it’s in some ways similar to how Google used Gmail’s extremely large storage capacity to make Hotmail and Yahoo!’s premium e-mail offerings obsolete).

Besides the fact that it is free and tracks an extensive number of metrics, Google Analytics makes a lot of sense if you are using AdWords because it integrates nicely with it.

I do want to note that here at Viget Labs we are big fans of WebSideStory’s HBX Analytics package (which costs money) and have a significant number of clients that we help leverage it. HBX allows you to dig a little deeper and, from our perspective, offers the ability to segment audience a bit more finely (and more easily). Still, if you just want to get up and running with a stats package - almost as a taste test for learning what web analytics is all about - Google Analytics is a great place to start.

Below follow a couple of resources:

Conversion University

http://www.google.com/analytics/conversionuniversity.html

Google Analytics Blog

http://analytics.blogspot.com/

Help

http://www.google.com/support/analytics/

Add to Del.icio.us | Digg This | Leave a Comment

Ruby on Rails: Making the Jump to LiteSpeed

As RoR becomes more mainstream, hosting a Rails application in a production environment becomes increasingly important. There are numerous tutorials explaining how to cobble together mongrel, apache, lighttpd, fastcgi, and friends, but the amount of configuration can be daunting.

Why go to that much trouble when LiteSpeed “Just Works”™? For a basic “Hello World” application, performance compares very well to the cobbled together systems, and installing it takes less than five minutes. To summarize the screencast, here are the ten essential steps for implementing a name-based virtual host running on an Ubuntu server, although this will work on any OS supported by LiteSpeed:

Read the rest of this entry »

Add to Del.icio.us | Digg This | Leave a Comment

This Problem Doesn’t Happen Online

Uniroyal TV AdI was watching a little NBA on ESPN last night and hadn’t had a chance to store up some buffer on my DVR, so I was forced to watch the commercials (woe is me). Uniroyal Tires had an ad running that I’d noticed before enough to remember the soccer mom running over a board of nails that just happens to be in the parking space she’s backing into, presumably to show how the tires aren’t phased by nail punctures. (Side note: if my kids ever stand there making stupid faces while I run over a bunch of nails instead of telling me to stop long enough for them to move them, I’ll disown them.)

Most of the ad promotes some kind of giveaway that I tried to ignore but it ends with this line:

“It could be the best trip you take all summer!”

Which, since I was still recovering from my Thanksgiving excesses, made me laugh out loud. Summer is long gone. Then I noticed this fine print:

Uniroyal TV Ad date

August 31, 2001? Who is paying attention to the ads that run on TV anymore?

Online, your customers are, that’s who. That’s why this wouldn’t happen on the web. If you’re fostering the right kind of community and engaging your audience the right way, as soon as a problem like this gets out, they’ll let you know about it, and you can fix it quickly. Encouraging this participation from your visitors is considered very Web 2.0, but it’s really been around as long as email and the Web — it’s all about making it easier for your customers to communicate with you effectively.

Reducing communication hurdles isn’t always easy, and for a lot of companies it creates new and unexpected challenges (what do we do with all that email?). Remember, though, that every chance to communicate with a customer, regardless of what sparked it, is an opportunity to strengthen your relationship with that person and market your company.

The negative of this new reality is that some companies take advantage of their active audience by overvaluing speed-to-market and skimping on quality. That, however, is a whole different blog post …

Update: As you can see from the comment below, Jill from Uniroyal contacted me and I gave her the specifics she needed to give the local ad buyer a newer ad to run. No word yet if Uniroyal plans to more actively engage their online audience (or send me a free set of tires as a ‘thank you’).

Add to Del.icio.us | Digg This | Leave a Comment

The Case for Accessibility

The Issue

If your organization has ever worked with the government, you have probably heard the term ‘Section 508 Compliance.’ If you’ve never tried to be ‘508 compliant’ before, it may sound a bit scary. The reality of the situation is that if your web site uses proper and up-to-date code, you’re probably fairly close. Nevertheless, it will require some extra time and testing to achieve this goal.

What’s important to understand is why you’re making the effort. 508 compliance is a legislative step toward making the internet available and accessible to people with various disabilities, who may use assistive technologies. While most of your audience may be fully sighted, hearing, and able to use a mouse, there are those who aren’t or can’t. The key to accessibility is making sure that all relevant content is communicated to everyone that uses your site and that actions can be completed using only a keyboard.

Target.com: A Case Study

Read the rest of this entry »

Add to Del.icio.us | Digg This | Leave a Comment

Getting Started With RJS in Rails

One of the features of Rails that makes it a great framework for building the next generation of “Web 2.0″ applications is its tight integration with the script.aculo.us JavaScript library. What this means for your application is the ability to dynamically update the display based on the results of an action (in this case ‘/task/mark_complete’):

def mark_complete
  begin
    @task = Task.find(params[:id])
    @task.task_status_id = TaskStatus::COMPLETE
    @task.save
  rescue ActiveRecord::RecordNotFound
    render :nothing => true
    return
  end
  render_text @task.status.description
end

Adding this code in a view template is all we need to have our display automatically update:

<p><strong>Status:</strong>
   <span id="task-status-<%= @task.id %>"><%= @task.status.description %></span></p>
   <p><%= link_to_remote 'Mark as Complete',
    :update =>, 'task-status-' + @task.id.to_s,
    :url => {:controller => 'task', :action => 'mark_complete', :id => @task %></p>

This works great for those times when we only need to update a single DOM element on a page. What about when we need to update multiple pieces of content on the same page? One solution that has worked quite well for us is the use of RJS templates in Rails.

Read the rest of this entry »

Add to Del.icio.us | Digg This | Leave a Comment

Tagging Text Automatically

Classifications are important; we do better as users when we can use a well-structured classification scheme to find information we’re looking for. In the web 1.0 world, that played out in a hierarchy imposed by site designers (typified in the eternal sitemap) that the audience was forced to work with. Web 2.0 saw a move away from this predefined architecture and towards audience-defined taxonomies (sometimes called folksonomies) built on tags - end users associate tags with pieces of content, and use various mechanisms to navigate between similarly-tagged items.

The Problem

Tagging is a great strategy in certain circumstances, but it has a few important drawbacks. The one we’ll talk about here is the blank-state problem: if you’re relying entirely upon the audience to generate your tags, then new content in a system suffers an inherent disadvantage. When a browser comes to the site, they’ll explore the existing tag architecture, but they won’t find the new content (since it hasn’t been tagged yet). They may still be able to find it via some other mechanism (search, for example), but unless they then tag it the content will stay buried. It’s a rich-get-richer situation - well-tagged content will be found and tagged more often, while under-tagged content will not be found and will remain under-tagged.

Read the rest of this entry »

Add to Del.icio.us | Digg This | Leave a Comment

Our Clients in the News

Here at Viget Labs we work with a variety of companies in the Washington, DC area. It was nice to see a couple of them prominently featured in the Business section of today’s Washington Post. The top story, about the Carr Empire, includes a picture of Angie O’Grady, president of Preferred Offices, a Carr Company and a long-time Viget Labs client.

Just below the Carr article is a story on SunRocket and their deal to provide Internet phone service for GE Phones. We have been providing consulting, web analytics, and email marketing services to SunRocket since they got started a couple of years ago.

It’s always nice to read about the successes of our clients, especially ones that we have been working with for a while. Just as I was about to put down the Post, I flipped to page D6 to notice one more Viget client - Vanda Pharmaceuticals. They had a quick mention in the “Market Movers” section - with a week’s change in stock price of 46%, not bad!

Add to Del.icio.us | Digg This | Leave a Comment

To Blog or Not to Blog?

That is the question for many of today’s businesses and organizations. And, it is a difficult one regardless of the shape and size of your company.

There is no “quick fix” for determining if blogging is right for you. I’ve worked with organizations with less than twenty people and thinking through their blog strategy was still very tough work.

A simple place to start is to answer the following questions.

What is my goal with blogging? What benefit(s) - if any - will blogging yield to my web efforts?

It would be easy to rattle off things like help with Search Engine Optimization, develop potential sales leads, or increase transparency with customers.  But, that’s not the whole story.

Charlene Li provides a nice framework for thinking through blog strategy, or more specifically on how to calculate the ROI of blogging.  She notes that, along with goals (benefits), come costs and risks.  After identifying these three elements, she writes:

“… simply divide the benefits by the costs + risks to arrive at the ROI. The key is what to use it for – it’s not enough, I believe, to use the ROI calculation only to justify a blog. It should also be used to manage and optimize the performance of the blog on an ongoing basis.”

Her research in this area is not yet complete; but, her post provides more than considerable first steps in quantifying blogging ROI.

Add to Del.icio.us | Digg This | Leave a Comment