Caius Theory

Now with even more cowbell…

Adding XHTML output validation to Cucumber stories

At the 2009 Barcamp Leeds I attended a talk by Neil Crosby where he talked about automated testing, and about how he felt there was a gap in everything that people were testing. Everyone has unit tests, and people are doing full stack testing too, but no-one (so he feels) does XHTML/CSS/JS validation as part of their automated test suite. And certainly from what I've seen on the mainstream Ruby site's about testing, I agreed with him.

So after his talk I had a quick look at his frontend test suite, and started wondering where exactly I would fit frontend validation testing into my workflow. Would it be part of my unit tests (RSpec), or part of the full stack tests (Cucumber)? As you've probably guessed by the title of this post, its ended up going into my cucumber tests. Since the initial play its been something I've mused about occasionally, but not something I've actively looked into how to implement as part of my test workflow.

Fast-forward a few weeks from Barcamp Leeds and I see a news article in my feed reader entitled "Easy Markup Validation" which gets me hopeful someone's solved this frontend validation thing easily for Rubyists. A quick read through and I'm sold on it and installing the gem. Opened an existing project I'm working on which has a fairly extensive test suite (both unit tests & full stack tests) and tried to slot the validation into my controller unit tests.

Problem with doing this is by default RSpec-rails doesn't generate the views in your controller specs. At that point I realised I was already generating the full page when I was doing a full stack test using culerity and cucumber. So why not just add a cucumber step in my stories to validate the HTML on each page I visit? Mainly because its not enough of a failure for this app to have invalid XHTML markup. Having valid markup would be nice, but I'd rather have it as a separate test to my stories in some way.

Currently I just do that by only validating if ENV["VALIDATION"] is set to anything, so a normal run of my cucumber stories will just test the app does what its supposed to do. If I run them with VALIDATION=true then it will check my markup is valid as well.

features/support/env.rb

require "markup_validity" if ENV["VALIDATION"]

features/step_definitions/general_steps.rb

Then %r/the page is valid XHTML/ do
  $browser.html.should be_xhtml_strict if ENV["VALIDATION"]
end

features/logging_in.feature

Feature: Logging in
  In order to do stuff
  As a registered user
  I want to login

  Scenario: Successful Login
    Given there is a user called "Caius"

    When I goto the homepage
    Then the page is valid XHTML

    When I click on the "Login" link
    Then I am redirected to the login page
    And the page is valid XHTML

    When I enter my login details
    And I click "Login"
    Then I am redirected to my dashboard
    And the page is valid XHTML

Now when I run cucumber features/logging_in.feature, it doesn't validate the HTML, it just makes sure that I can login as my user and that I am redirected to the right places. But if I run VALIDATION=true cucumber features/logging_in.feature, then it does validate my XHTML on the homepage, the login page and on the user's dashboard. If it fails validation then it gives you a fairly helpful error message as to what it was expecting and what it found instead.

From a quick run against a couple of stories in my app I discovered that I've not been wrapping form elements in an enclosing element, so they've been quickly fixed and now they validate. Now I realise this gem is only testing XHTML output, and doesn't include CSS or JS validation, but from a quick peek at the gem's source it should be fairly easy to add both of those in I think, although again they aren't major errors for me yet in this app.

View Raw Source

So I write this blog using Markdown because I'm a human and writing stuff <strong>with</strong> tags is just WRONG. Thankfully, Gruber solved this problem by writing markdown.

Now on the markdown page he says:

The best way to get a feel for Markdown’s formatting syntax is simply to look at a Markdown-formatted document. For example, you can view the Markdown source for the article text on this page here: http://daringfireball.net/projects/markdown/index.text

(You can use this ‘.text’ suffix trick to view the Markdown source for the content of each of the pages in this section, e.g. the Syntax and License pages.)

And ever since I noticed that I've always read his articles using the '.text' trick. One of the plugins I've been meaning to write for habari is one that replicates this '.text' behaviour. So tonight I decided to try and write it, started picking through the Plugin documentation in preparation. Got a bit stuck with it as I've been out of the habari development loop for a few months, popped into #habari and asked if I was thinking along the right lines.

Few minutes later Owen pops up and sends me a link to plaintext.plugin.php, which does exactly what I was trying to do! Couple of tweaks later (switching it to '.text' instead of '.md') and its installed and working on this blog. Feel free to view the raw source of this post. Or any other post on this site.

Updated 2009-01-31

Added to the habari-extras repo as the Plaintext plugin.

Merry Testing

Just a few examples of the same test written in a few languages. Its testing setting the date on an object that is created in the tests' setup method already. These fall under the unit testing, rather than full-stack testing.

Testing in ObjC with OCUnit

// Add a date and time
- (void)testSettingDate
{    
    NSDate *theDate = [NSDate date];        
    
    STAssertNoThrow([calc setDate:theDate], @"Shouldn't raise an exception");
    // And it should match when pulled out as well
    STAssertEqualObjects([calc date], theDate,
                         @"%@ should match %@",
                         [calc date], theDate);

}

Testing in Ruby using RSpec

it "should set the date successfully" do
  the_date = Date.today

  @calc.date = the_date
  # And it should match when pulled out as well
  @calc.date.should == the_date
end

Testing in Ruby using Test::Unit

def test_setting_date
  the_date = Date.today
  @calc.date = the_date
  # And it should match when pulled out as well
  assert_equal(@calc.date, the_date)
end

Testing in PHP using PHPUnit

function testSettingDate()
{
    $date = date();
    $calc->date = $date;
    # And it should match when pulled out as well
    $this->assertEquals($calc->date, $date);
}

Command line tricks: Scripting Languages

To search your php.ini file quickly and easily with the option to use regular expressions, I tend to drop back to the cli. The reason for this is I can easily parse the output of phpinfo() with grep, and can do various things with the output, could even pass it to a script if I really wanted to.

Here is the line I use to search phpinfo()

echo "<?php phpinfo() ?>" | php | grep -i $search_string

It passes the string through the php interpreter and then searches through it with grep.

You can also do other nifty things with the shell & php + ruby especially (though I imagine python & perl work in the same way.) For instance I wanted to see if the following ruby would return the number of seconds since the epoch till now.

puts Time.now.to_i

Now I could fire up a PHP page and do something like the following

<?php
  echo "php: " . time() . "\n";
  echo "ruby: " . `ruby -e 'print Time.now.to_i'` . "\n";
?>

But what if I've not got a web server with PHP running on the machine I'm using? Well then I could drop back to the shell and run it through php using cat as a way to insert multiple lines, and it would look like the following

cat <<PHP | php
<?php
  echo "php: " . time() . "\n";
  echo "ruby: " . `ruby -e 'print Time.now.to_i'` . "\n";
PHP

php: 1203004463
ruby: 1203004463

Now this works, but why do I want to remember all that php, and seeing as I have to drop back to the shell to access the ruby statement, why not just let the shell do all the work? So after a few seconds thinking, I came up with this

ruby -e 'puts "ruby: #{Time.now.to_i}"' && \
  echo '<?php echo "PHP: " . time() . "\n" ?>' | php

This runs the ruby code through ruby and the php code through php without dropping back to the shell from within a language interpreter :)

Update:

Fangel pointed out php -r is the equivilent of ruby -e so the final commands could just be:

ruby -e 'puts "ruby: #{Time.now.to_i}"' && \
php -r 'echo "PHP: ".time()."\n";'

Why do I love Ruby?

So mother (who can't program) just posed me the question

Why is Ruby your favourite programming language?

Me being a show off jumped straight into TextMate and banged out some code in real time to show her. First up, a quick little one-liner of Ruby code to output a String:

puts "Hello World"
# => "Hello World"

So she goes, "Sure, but whats so brilliant about that?" So I just decide to reverse the string, have it output in reverse order:

puts "Hello World".reverse
# => "dlroW olleH"

Then the next question comes, "So what makes that so much easier than in other languages?" Well now I was thinking on the spot about which other language I can bang out a quick example in without having to look up too much information. PHP seems the logical choice, being the language I know best behind Ruby.

Thinking about how to do it in PHP, I can't think of a function to reverse the content of a string, but I know that array_reverse() exists, so I just split it into an array and reverse that array. Only problem is I can't remember how to split a string by "", I don't think explode( "", $var ) does the job. So I quickly jump in and write the following code to test my concern.

<?php
  $a = "Hello World"
  $b = explode( "", $a );
  $c = array_reverse( $b );
  echo implode( "", $c );
?>
# => ERROR

The reason for the error is because I've missed a semi colon off the end of line 2, to this I get the response, "well thats certainly not as nice as ruby." Just because one little character is missing!

So I fix the semi colon and run it again, now I get an error complaining about explode not being able to split by a missing delimiter (the empty string - "") So I go hunting through the php.net docs and find str_split(), which does exactly what I want it to.

In replacing explode() with str_split() and running it via the php command line binary, I realise that I haven't got any \n (newlines) at the end of it, so it doesn't display nicely in the terminal. I thus update the script to the following and show her the result:

<?php
  $a = "Hello World";
  $b = explode( "", $a );
  $c = array_reverse( $b );
  echo implode( "", $c )."\n";
?>
# => "dlroW olleH"

And so she goes away seeing why I prefer Ruby to other languages for most programming I do. There are things Ruby fails at (and don't get me started on why rails isn't going to replace php!) and other places where it succeeds very well.

But each to their own, and my own favourite is Ruby!

Update

As pointed out in the comments, if I had looked a bit further I would've found strrev() which does the same as the reverse method in Ruby. So in fact the final code would be:

puts "Hello World".reverse

vs

<?php
  echo strrev( "Hello World" );
?>

So it turns out this was a bad way to show why I prefer Ruby to PHP code wise to mother, think I might have to just bite the bullet and write about why I prefer object.method to method( object )!