davideisinger.com

My personal website
Log | Files | Refs | README

index.md (3283B)


      1 ---
      2 title: "Testing Your Code’s Text"
      3 date: 2011-08-31T00:00:00+00:00
      4 draft: false
      5 canonical_url: https://www.viget.com/articles/testing-your-codes-text/
      6 ---
      7 
      8 The "Ubiquitous Automation" chapter of [*The Pragmatic
      9 Programmer*](https://books.google.com/books?id=5wBQEp6ruIAC&lpg=PA254&vq=ubiquitous%20automation&pg=PA230#v=onepage&q&f=false)
     10 opens with the following quote:
     11 
     12 > Civilization advances by extending the number of important operations
     13 > we can perform without thinking.
     14 >
     15 > --Alfred North Whitehead
     16 
     17 As a responsible and accomplished developer, when you encounter a bug in
     18 your application, what's the first thing you do? Write a failing test
     19 case, of course, and only once that's done do you focus on fixing the
     20 problem. But what about when the bug is not related to the *behavior* of
     21 your application, but rather to its configuration, display, or some
     22 other element outside the purview of normal testing practices? I contend
     23 that you can and should still write a failing test.
     24 
     25 **Scenario:** In the process of merging a topic branch into master, you
     26 encounter a conflict in one of your ERB files. You fix the conflict and
     27 commit the resolution, run the test suite, and then deploy your changes
     28 to production. An hour later, you receive an urgent email from your
     29 client wondering what happened to the footer of their site. As it turns
     30 out, there were *two* conflicts in the file, and you only fixed the
     31 first, committing the conflict artifacts of the second into the repo.
     32 
     33 Your gut instinct is to zip off a quick fix, write a self-deprecating
     34 commit message, and act like the whole thing never happened. But
     35 consider writing a rake task like this:
     36 
     37 ```ruby
     38 namespace :preflight do
     39   task :git_conflict do
     40     paths = `grep -lir '<<<\|>>>' app lib config`.split(/\n/)
     41 
     42     if paths.any?
     43       puts "ERROR: Found git conflict artifacts in the following files\n\n"
     44       paths.each {|path| puts " - #{path}" }
     45       exit 1
     46     end
     47   end
     48 end 
     49 ```
     50 
     51 This task greps through your `app`, `lib`, and `config` directories
     52 looking for occurrences of `<<<` or `>>>` and, if it finds any, prints a
     53 list of the offending files and exits with an error. Hook this into the
     54 rake task run by your continuous integration server and never worry
     55 about accidentally deploying errant git artifacts again:
     56 
     57 ```ruby
     58 namespace :preflight do
     59   task :default do
     60     Rake::Task['cover:ensure'].invoke
     61     Rake::Task['preflight:all'].invoke
     62   end
     63 
     64   task :all do
     65     Rake::Task['preflight:git_conflict'].invoke
     66   end
     67 
     68   task :git_conflict do
     69     paths = `grep -lir '<<<\|>>>' app lib config`.split(/\n/)
     70     
     71     if paths.any?
     72       puts "ERROR: Found git conflict artifacts in the following files\n\n"
     73       paths.each {|path| puts " - #{path}" }
     74       exit 1
     75     end
     76   end
     77 end
     78 
     79 Rake::Task['cruise'].clear
     80 
     81 task :cruise => 'preflight:default' 
     82 ```
     83 
     84 We've used this technique to keep our deployment configuration in order,
     85 to ensure that we're maintaining best practices, and to keep our
     86 applications in shape as they grow and team members change. Think of it
     87 as documentation taken to the next level -- text to explain the best
     88 practice, code to enforce it. Assuming you're diligent about running
     89 your tests, every one of these tasks you write is a problem that will
     90 never make it to production.