Improving My Testing

I spent a good portion of today looking at integration tests.

In the normal course of things, a website undergoes integration tests from an external source; in my career it’s something like selenium for external testing of a website, and faraday for testing a RESTful API.

I’ve been thinking a lot, though, about where selenium fits into the test cycle. There’s a kind of test that I’ve seen selenium used for a lot, but is not its strong point, and that’s testing simple workflows: does /blogpost/new contain a title string, or does /index contain a sign_in link? Selenium _can_ do these things, but I think its real strong suit is complex scenarios: can I log in, then create a blog post, then assign the post to a calendar date, then make sure that the calendar picker doesn’t let me assign two posts to a date, and so on. Lots of steps, each of which takes you further into the application.

Simple stuff like checking if the front page is actually present can absolutely be covered by selenium, but it seems like I see two problems:

  • selenium tests take a real time to maintain, even for relatively simple changes.
  • selenium can be integrated into the build system, but it’s hard to integrate it into the testing cycle in such a way that developers get feedback before committing their code.

I wanted to solve both of these, and in rails it looks like the built in integration test stuff really solves both in a neat way. It sits there, between the unit test stuff and the full blown complex testing scenarios, providing a simple to maintain, integrated set of tests that nonetheless can be very useful.

Here’s a few downright useful tests I put together with a hand from a couple of guys with more UI experience than I have. Start by generating the integration test:

rails generate integration_test blogs

Now, here’s a neat set of simple tests:

class BlogTest < ActionDispatch::IntegrationTest
  test "browse index" do
    get "/"
    assert_response :success
   assert_select "h1"
  end

  test "browse new page" do
    get "/blogs/new"
    assert_response :success
   assert_select "input"
  end
  test "Find some specific field" do
    get "/blogs/new"
    assert_response :success
    assert_select "div.field"
  end
  test "Find some specific text area" do
    get "/blogs/new"
    assert_response :success
    assert_select "textarea[name='blog[body]']"
  end
end

If you’ve already installed capybara, the syntax is a little different but not bad:

 describe "GET /blogs" do
   it "works! (now write some real specs)" do
   # Run the generator again with the --webrat flag if you want to use webrat methods/matchers
   visit new_blog_path
   fill_in "Title", with: "Jamandbees' awesome blogness"
   fill_in "Body", with: "Jamandbees writes about sadness"
   click_button "Create Blog"
   page.should have_content "Blog was successfully created."
   page.should have_content "blogness"
  end
end

That’s literally all there is to some very basic integration tests in rails.

I’m a professional QA resource; my idea about QA is that a QA person should know and understand the stack they’re working with as well as the developers understand it, and be able to comment  effectively and, yes, write code in the same language the developers are working in. As a QA person working in rails, I have known the full stack back to back in a basic way, sufficient to be able to sit down, read code with developers and comment upon it with them. If you can’t code review the codebase, there are entire stacks and oodles of bugs you cannot find.

I gave a presentation today about integration testing in rails and got clearance to start writing some of the basic integration tests that will improve our codebase. I can write these, have them integrated in the build and be confident that my (frankly, excellent) team of colleagues in development will be able to maintain them. I think that when an application is still young and in flux, having the QA person write tests and developers easily maintain them is a good balance for the team.

Advertisements

New Project — Daily Coding

I heard today about a guy who committed to commit some finished piece of his own code to a project every day for a year.

I thought it sounded good. So I decided to start with some project euler.

https://github.com/jamandbees/project_euler

Hopefully, the various rails projects I have in mind will eventually be part of this, but I wanted to start somewhere small.

Ruby 1.9.3 on Mac OS X Lion with XCode 4.3

I wanted to install rails 3.2.4 on Mac OS 10.7. The system ruby is 1.8, but I wanted to run against 1.9.3, and it was tricky getting everything working with XCode 4.3.

I wanted to use RVM, but right now RVM spits out an error telling you that 1.9.3 is kind of covered with XCode 4.3, that prior versions of ruby aren’t supported with 4.3, and that you might want to install OSX-GCC-Installer and remove XCode. If you want to go down that path, the OSX-GCC dude seems like a nice bloke: http://kennethreitz.com/xcode-gcc-and-homebrew.html

I didn’t! As such, I decided to see if homebrew would install ruby 1.9.3 (it does) and how hard it would be to switch between its version of ruby and the system ruby (it’s trivial).

  • Remove rvm if you’ve installed it:
    rm -Rf ~/.rvm
  • Install XCode 4.3 from the app store.
    Once installed, open XCode -> Preferences -> Downloads -> Command Line Tools. Download ’em.
  • Install HomeBrew: http://mxcl.github.com/homebrew/. Do your best with their post-install instructions. I especially found it useful to uninstall macports http://guide.macports.org/chunked/installing.macports.uninstalling.html
  • Install ruby 1.9.3: brew install ruby
  • Open .profile (or .bashrc or whatever bash config file you’re using) and add
    PREPATH=$PATH
    #homebrew suggests putting usr/local/bin before /usr/bin
    export PATH=/usr/local/bin:$HOME/.gems/bin:$PATH
    alias unbrew="export PATH=${PREPATH}"
    

    Now, if you want to use the system ruby you run unbrew from the command line

Sockets, Arbitrary Ruby and C

I’ve had this small project in mind to write a server which would execute arbitrary ruby. I didn’t want to have a concept of state, so assignment and memory management weren’t a big deal.  It should:

1. Accept a class method, like puts “Hello, world!”
2. Output on the server “Hello, world!”
3. Output on the client “puts “Hello, world!””

I knew GServer existed in the stdlib, but didn’t know how to work it. I saw a neat trick on the peepcode  screencast with Aaron Patterson: download the source tree and ask _that_ your questions, don’t bother with the docs.

I downloaded ruby’s source tree, kind of nervous, and found the GServer implementation using sublime text’s fuzzy search function. The comments said to just inherit from the class and implement the serve method, and all would rock.

I was surprised by how much cleared reading the source and comments were than reading the rdoc that’s generated from those same source and comments. I was reading through the code really happily, learning about GServer, and managed to get the functionality I was looking for in about 20 minutes. If you want to download the code, it’s available on github: https://github.com/jamandbees/arbitrary-server

One of the neat things reading the code was that I actually read the implementation of each method, and I noticed something in the start method that got me thinking. There’s a class to create a new TCPServer:

 @tcpServer = TCPServer.new(@host,@port) — from GServer.rb

The requires for the class are socket and thread, so I assumed this came from socket. I read socket.rb, though, and I honestly didn’t see a TCPServer definition, so I checked its requires: socket.so.

Socket.so is a compiled library. I did a quick search for socket.c and found documentation in there that references TCPServer.new, but which doesn’t seem to have any implementation that would recognise the name “TCPServer.new”.

Socket.c includes rubyserver.h. Reading that, I saw these two lines:

extern VALUE rb_cTCPServer;

void rsock_init_tcpserver(void);

So we’re mentioning a tcpserver in an included library, finally!

From here, I didn’t know where to go.I did a search of the source tree for tcpserver and found tcpserver.c. It also includes rubyserver.h, so presumably somewhere in that include is where the relationship between socket and tcpserver is created, but I can’t see where.

I do see where the class is made, though:

void
rsock_init_tcpserver(void)
{
  /*
  * Document-class: TCPServer < TCPSocket
  *
  * TCPServer represents a TCP/IP server socket.
  *
  * A simple TCP server may look like:
  *
  * require 'socket'
  *
  * server = TCPServer.new 2000 # Server bind to port 2000
  * loop do
  * client = server.accept # Wait for a client to connect
  * client.puts "Hello !"
  * client.puts "Time is #{Time.now}"
  * client.close
  * end
  *
  * A more usable server (serving multiple clients):
  *
  * require 'socket'
  *
  * server = TCPServer.new 2000
  * loop do
  * Thread.start(server.accept) do |client|
  * client.puts "Hello !"
  * client.puts "Time is #{Time.now}"
  * client.close
  * end
  * end
  *
  */
  rb_cTCPServer = rb_define_class("TCPServer", rb_cTCPSocket);
  rb_define_method(rb_cTCPServer, "accept", tcp_accept, 0);
  rb_define_method(rb_cTCPServer, "accept_nonblock", tcp_accept_nonblock, 0);
  rb_define_method(rb_cTCPServer, "sysaccept", tcp_sysaccept, 0);
  rb_define_method(rb_cTCPServer, "initialize", tcp_svr_init, -1);
  rb_define_method(rb_cTCPServer, "listen", rsock_sock_listen, 1); /* in socket.c */
}

So, as long as I can get from tcpserver.c through to socket.c, I think I’ll be okay.
Funny how you sometimes wander down paths.