Category Archives: drupal

Test-driven development and happiness

Me: Happiness is a test suite that passes.
@philiph: Do you practice test-driven development for your happiness?
Me: Why, yes, actually, I do. It gives me a tangible sense of accomplishment and minimizes my mouse-clicking. =)

Developers find their own balance of how much project structure works with them. Some people like seat-of-their-pants coding. Others want detailed architecture diagrams. Me, I’m getting the hang of agile development practices, and I really enjoy using them.

Test-driven development, for example. Yes, I could just plunge ahead and write Drupal code, and I could test it by clicking on buttons and typing into forms. I don’t particularly like using the mouse or doing repetitive actions, so I write tests for functionality and occasionally for web interaction. Tests also mean that  I can check small pieces of functionality before I have to build a web interface. And when something breaks – not if, but when – tests help me narrow down the error.

It’s so satisfying to see the tests pass, too.

There are tests that exercise functionality, and tests that set up test data just the way we like it so that we can demonstrate features or try things out using the web interface. One of my team members showed me a wonderful technique for repeatable, well-structured test data by using a spreadsheet to generate PHP code. I’ve been extending the pattern for other things.

Drupal + Simpletest is awesome. It can’t handle everything, but it makes my Drupal life better. Happy developers write happy code!

Drupal, SimpleTest, and the node access API

Setting up Simpletest and Drush on Drupal 6.x:

  1. Download and enable Simpletest with drush dl simpletest; drush en -y simpletest
  2. Download to your ~/.drush/drush_extras directory. This version allows you to run a single test from the command-line.
  3. Create a custom module with a tests/ subdirectory, and write your tests in it. (See this Lullabot Simpletest tutorial.)

We’re starting another Drupal project. While the IT architect is working on clarifying the requirements, I volunteered to implement the risky parts so that we could get a better sense of what we needed to do.

The first major chunk of risk was fine-grained access control. Some users needed to be able to edit the nodes associated with other users, and some users needed to have partial access to nodes depending on how they were referenced by the node. Because there were many cases, I decided to start by writing unit tests.

SimpleTest was not as straightforward in Drupal 6.x as it was in Drupal 5.x. There were a few things that confused me before I figured things out.

I wondered why my queries were running off different table prefixes. I didn’t have some of the data I expected to have. It turns out that Simpletest now works on a separate Drupal instance by default, using a unique table prefix so that it doesn’t mess around with your regular database. I’m doing this on a test server and I want to be able to easily look up details using SQL, so I needed to add this to my test case:

class ExampleTestCase extends DrupalWebTestCase {
  function setUp() {
    global $base_url;
    $this->originalPrefix = $GLOBALS['db_prefix'];
  function tearDown() { }

I also didn’t like how the built-in $this->drupalCreateUser took permissions instead of roles, and how it created custom roles each time. I created a function that looked up the role IDs using the {role} table, then added the role IDs and roles to the $edit['roles'] array before creating the user.

Lastly, I needed to add the Content Profile operations to my custom user creation function. I based this code on content_profile.test.

// create a content_profile node
$edit = array(
  'title' => $account->name,
  'body'  => $this->randomName(),
$this->drupalPost('node/add/' . str_replace(' ', '-', $role), $edit, t('Save'));

It would’ve been even better to do this without going through the web interface, but it was fine for a quick hack.

I had the setup I wanted for writing test cases that checked user permissions. I wrote functions for checking if the user could accept an invitation (must be invited, must not already have accepted, and must be able to fit). SimpleTest made it easy to test each of the functions, allowing me to build and test blocks that I could then put together.

The code in content_permission.module turned out to be a good starting point for my field-level permissions, while the Drupal node access API made it easy to handle the user-association-related permissions even though I used node references instead of user references.

It was a good day of hacking. I wrote tests, then I wrote code, then I argued with the computer until my tests passed. ;) It was fun seeing my progress and knowing I wasn’t screwing up things I’d already solved.

If you’re writing Drupal code, I strongly recommend giving SimpleTest a try. Implementing hook_node_access_records and hook_node_grants is much easier when you can write a test to make sure the right records are showing up. (With the occasional use of node_access_acquire_grants to recalculate…) Otherwise-invisible Drupal code becomes easy to verify. The time you invest into writing tests will pay off throughout the project, and during future work as well. Have fun!

How to use Drush to download and install Drupal modules

One of the best things about building websites with Drupal is that there are thousands of modules that help you quickly create functionality.

To set things up, you need to download Drush and add it to your path. For example, you might unpack it into /opt/drush and then add the following line to your ~/.bashrc:

export PATH

Reload your ~/.bashrc with source ~/.bashrc, and the drush command should become available. If you’re on Microsoft Windows, it might need some more finagling. (Or you can just give up and use a virtual image of Linux to develop your Drupal websites. You’ll probably end up much happier. ;) )

Once you’ve installed Drush, what can you do with it?

Drush is a huge time-saver. For example, I install dozens of modules in the course of building a Drupal website. Instead of copying the download link, changing to my sites/all/modules directory, pasting the download URL into my terminal window after wget, unpacking the file, deleting the archive, and then clicking through the various module enablement screens, I can just issue the following commands to download and enable the module.

drush dl modulename
drush en -y modulename

(The -y option means say yes to all the prompts.)

So much faster and easier. You can use these commands with several modules (module1 module2 module3), and you can use drush cli to start a shell that’s optimized for Drush.

Drush is also useful if you’ve screwed up your Drupal installation and you need to disable themes or modules before things can work again. In the past, I’d go into the {system} table and carefully set the status of the offending row to 0. Now, that’s just a drush dis modulename.

Drush has a bucketload of other useful commands, and drush help is well worth browsing. Give it a try!

Drupal Features and Drush: updating our development workflow

I’m working with two other people on a Drupal project, so we’re coordinating our work through a Subversion source code repository. A lot has changed in Drupal since the days when I dived into the source code to figure out the code I needed in order to duplicate the configuration changes I made through the web interface (Drupal staging and deployment: it’s all code). Now, the Features module can export various configuration bits as a module that you can check into your source tree and enable on your site. It will even show you which settings you’ve overridden through the web interface, so you can regenerate the code and make sure everything’s included.

Drush (the Drupal shell) has some commands that make Drupal features even easier to use. For example, I use drush features-diff <feature_name> to see which settings I’ve changed, and drush features-update to re-export the settings to source code.

Because we’ll be using Features to share our changes instead of working off SQL backups, I need to make sure that I’ve included all the relevant components in the features I create. One way to test that is to use Backup and Migrate to save my configured database (just in case!), load a previous backup, enable the feature, and confirm that everything works as expected.

Tests using either SimpleTest or Selenium would be the best way to confirm everything is working, of course. When Stuart comes back on Monday, he can help us set up an environment using hudson as a continuous integration server. Stuart has set up Selenium tests before, and it might be possible to use simpletest with hudson also.

Saving development time through virtual appliances
Photo (c) 2008 JakesDad – Creative Commons Attribution Licence 2.0

I’m beginning to be a big fan of virtual images for development work, because they save me from having to have the setup above. I already bring two laptops – don’t need more!

By downloading and customizing an image of a system that is already configured for typical development tasks, I can save myself a lot of administrative time – and keep development work more cleanly separated from the other files on my computer.

Both VMWare and Virtualbox have many virtual appliances available, and you can start using them with the appropriate player. Both VMWare and Virtualbox are free for personal, non-commercial use. I’ve taken advantage of a VMWare licensing program at work, installing VMWare Workstation so that I could take snapshots of my development environment if necessary.

I picked the Turnkey Drupal 6 distribution, a 175MB download. Installing Apache, MySQL, and PHP on Ubuntu is easy, but it was good to be able to take advantage of Turnkey’s support for https and other niceties. I may still have to install everything onto the production server manually, but at least we can do the setup easily. I changed the passwords from the defaults, of course.

I didn’t think it would be this easy. I had avoided virtualization for a while because it had felt slow and clunky the last time I tried it years ago. With 3GB of memory, this tablet PC can run both Windows 7 and the development server images just fine. Running Linux inside Microsoft Windows (instead of the other way around) might have helped, too. Setting up networking was a breeze, too. I chose bridged networking, which made the virtual machine seem like a new computer on the network.

The only quibble I’d like to fix is definitely a nerdy one – I’m back to QWERTY in the virtual machine, because it ignores the Dvorak keyboard mapping I’ve chosen on the host operating system. It’s an easy matter to change this on Linux (“loadkeys dvorak” at the command-line), but an even easier (and more responsive) way to work with this is to use ssh to connect to the virtual image.

Full speed ahead!

Notes from DrupalCampToronto 2010

Update May 21, 2012: Sorry, sketches are missing!

I’m shifting from a emerging technologies consulting project (organizing executive workshops and brainstorming sessions) to Drupal development projects here in IBM, so I took the opportunity to attend DrupalCampToronto 2010 last Saturday. It was great to see a lot of activity around Drupal, and I’m looking forward to catching up with all the new features. =)

I wrote and sketched notes using Microsoft Onenote on my Lenovo X61T tablet. Check out my DrupalCampToronto 2010 sketchnotes in the gallery. Example:Sketch notes from conversion optimization(… there’s more – click on the image to see the rest of this!)

I still have a lot to do before my sketchnotes can be as pretty as these, but I had a lot of fun taking notes, and sketching helped me stay focused.

Some sessions covered things I could probably figure out from blog posts, articles, READMEs, slides, and handbook pages, but it was good to meet people and take a quick tour of what the community thought was important. I’m looking forward to reviewing the topics with a Drupal site at hand, so that I can experiment with these interesting ideas.

OneNote’s handwriting recognition got confused by the sketches, I think, but I can resummarize sessions here:

Conversion optimization: Think about your website as an asset. You can increase your return on investment by measuring and optimizing your conversion. Keep your audiences in mind, and use personas instead of just demographics in order to make them concrete. Establish trust through consistency and relevance. Create ongoing experiments, where you use Google Website Optimizer to test one thing at a time through split-testing. Make sure your offer pages pass the 6-second test (can people remember all the relevant details after a 6-second look at the website?). Sketchnotes for conversion optimization

Search engine optimization: There are a whole bunch of modules to help you with SEO on Drupal. Key ones: pathauto to add search engine keywords to the URL, path redirect to redirect old aliases, page title to set the page titles and target specific keywords, node words for metadata (including description – set this for better search engine listings), global redirect to avoid duplicate content penalties for multiple URLs, XML sitemap to aid in discovery and indexing, and SEO checklist for lots of other tips. The Zen theme is really handy because it puts your content earlier in the page, too. Sketchnotes for search engine optimization

An agile project management toolkit built with Drupal: Demo of the Fragile Solutions tool a company built to manage its projects. The code hasn’t been released as modules on and I think they’re not planning to package it, but they said they’re open to sharing the code if you contact them. Good use of Views + Panels for dashboards, plus custom modules for calculating velocity, tracking revision history when stories are moved across sprints. Good use of programmatic views for greater database independence. Interesting company-wide view of sprints (instead of individual project views) makes it easier to do forecasting on a company level. Sketchnotes for agile project management

If you give away the milk for free, they’ll buy the cow (Selling Drupal services): Focus on benefits, not technology. Lullabot has great criteria for leads (see Liza Kindred): must be nice people, and must have healthy budget and/or interesting projects. Use the qualification process to ask lots of questions, trying to figure out why you shouldn’t work with someone. Charge for diagnosis/discovery/design phase as well (see doctor example). Use business hours for calling people, not for developing. Books to check out: “Getting Naked” (Patrick Lencioni) and “The Win Without Pitching Manifesto” (Blair Enns, free). Great story illustrating show vs tell: Tupperware, hammers. Paraphrased here:

One of the selling points of Tupperware was that the plastic Tupperware containers were much less fragile than the glass containers popular then. At a big Tupperware sales convention, people got together to share notes. They found that one representative outsold the others by a significant margin. The other representatives asked him for his secret. He said that instead of telling potential customers that Tupperware was hard to break, he always took a hammer and tried to break the Tupperware in front of them.

The next year, sales improved as people started carrying hammers – but the same representative still outsold everyone. They asked him what he did. He said that he now gave potential customers the hammer so that they could try to break the Tupperware.

Showing people is better than telling people. Letting people experience the benefits is the best of all.

On a related note, someone in the session also told a story about a real estate agent who lets potential buyers park in the driveway and unlock the door with the house key, further giving people that sense of ownership before they discuss the deal. Sketchnotes for selling Drupal

The sessions on Panels 3: Panels 3 looks really cool. Looking forward to trying it out. Must check out the Total Control and Views Bulk Operation modules too, and keep in mind that Panels and CTools need to be upgraded at the same time. Sketchnotes for architecting with Panels 3 and Emma Jane’s talk