Tuesday, October 18, 2016

Setting up a Continuous Rails 5 TDD Feedback Loop with RSpec

RailsTDD

As part of a red-green-refactor cycle, I appreciate a smooth, fast feedback loop. The slower the loop; the more my attention gets to another shiny object and my concentration gets broken. This tutorial aims to help you achieve a smooth red-green-refactor loop.

By the end you should be able to:

  • Setup testing frameworks:
    • RSpec, Shoulda-Matchers, Database Cleaner, Capybara, Factory_girl_rails, Faker
  • Write a Model test
  • Improve TDD Feedback loop using Guard and Spring
  • Setup Notifications

Setup App

rails new exampleapp -T (-T does not generate test files)

Setup Testing Frameworks

Update the Gemfile Include the following gems in your Gemfile:

group :development, :test do
  gem 'rspec-rails', '~> 3.4'
  gem 'factory_girl_rails', '~> 4.5'
  gem 'capybara', '~> 2.5'
end
 
group :test do
  gem 'shoulda-matchers', '~> 3.0', require: false
  gem 'database_cleaner', '~> 1.5'
  gem 'faker', '~> 1.6.1'
end

Run bundle install

Note: If you have any problems installing gems, primarily NokoGiri, run the following commands:

xcode-select --install
bundle install

Setup RSpec

rails generate rspec:install

The install will generate a spec directory and some skeleton files, including a .rspec file, which will be used later.

Shoulda-Matchers

Shoulda-Matchers provide one line matchers for RSpec. We need to configure shoulda-matchers to work with RSpec by modifying the spec/rails_helper.rb file to include the following code snippet:

require 'rspec/rails'
 
require 'shoulda/matchers'
 
Shoulda::Matchers.configure do |config|
  config.integrate do |with|
    with.test_framework :rspec
    with.library :rails
  end
end

Setup Database Cleaner

To setup database_cleaner, make the following modifications to spec/rails_helper.rb. Once complete, database_cleaner will clean the database between each unit test and each test suite.

config.use_transactional_fixtures = false

Make a new directory called support inside of your spec directory:

mkdir spec/support

Inside the new support directory, create a new file called database_cleaner.rb and paste in the following:

RSpec.configure do |config|
 
  config.before(:suite) do
    DatabaseCleaner.clean_with(:truncation)
  end
 
  config.before(:each) do
    DatabaseCleaner.strategy = :transaction
  end
 
  config.before(:each, :js => true) do
    DatabaseCleaner.strategy = :truncation
  end
 
  config.before(:each) do
    DatabaseCleaner.start
  end
 
  config.after(:each) do
    DatabaseCleaner.clean
  end
end

Allow Rails to run this support file in it's setup. In rails_helper.rb, un-comment the following line:

Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f }

Setup Capybara

Since we've already got the Capybara gem installed, just add the following line to the top of spec_helper.rb file:

require 'capybara/rspec'

Setup Faker and Factory Girl

Faker gem generates random data for testing. We will use this with factory_girl_rails in making a factory. To integrate FactoryGirl with RSpec, add the following line in rails_helper.rb within the RSpec.configure block:

config.include FactoryGirl::Syntax::Methods

Create a factory

Create a directory named factories in your spec folder. In the factories directory, create a file named after your model. Ex. ideas.rb

***spec/factories/ideas.rb***
 
FactoryGirl.define do
  factory :idea do
    title       { Faker::Lorem.words(4) }
    description { Faker::Hacker.say_something_smart }
  end
end

This factory allows you to generate fake data based on data generated by Faker to be used by FactoryGirl in running our tests.

Let's write a test!

Now that we have our testing frameworks in place, let's write our first Model spec!

Create a file in your model/spec folder for your model:

***spec/models/idea_spec.rb***
 
require 'rails_helper'
 
RSpec.describe Idea, type: :model do
  it "has a valid factory" do
    idea = build(:idea)
    expect(idea).to be_valid
  end
end

Let's run the test from the terminal:

rspec spec/models/idea_spec.rb

This test will fail because we don't have an idea model. Let's create it!

rails g model Idea title:string description:string

This will want to overwrite the idea_spec.rb file and the spec/factories/ideas.rb file. Don't allow it, just enter 'n' for both. Then run:

rails db:migrate

Once the database has been migrated, lets run our test again.

rspec spec/models/idea_spec.rb

Green!

That feedback was good but it was a bit slow. Let's speed it up and gain more convenient feedback.

Improve TDD Feedback loop

Add the the following gems to your Gemfile:

group :development do
  gem 'guard-rspec', require: false
  gem 'spring-commands-rspec'
end
bundle install

Guard Setup

Guard is a neat gem that works with RSpec that watches your file system for changes and runs your test suite automatically. We need to initialize it, then we can run it

bundle exec guard init rspec
bundle exec guard

Spring Setup

Spring is new to Rails 5. This will setup our configuration once and then run tests repeatedly without having all the extra configuration overhead between each run. If you change rails configuration, you will need to restart the Spring.

For just one single test, this shaved a solid 5 seconds off of each test run!

spring binstub --all

Now, let's notify Guard to use Spring when running specs. In the Guardfile, modify the following line from:

guard :rspec, cmd: "bundle exec rspec" do

to:

guard :rspec, cmd: "bin/rspec", all_on_start: true do

Then run guard:

bundle exec guard

There should be a line in the output that says "Running via Spring preloader in process..." From your idea_spec.rb file, trigger a save. You'll see in the terminal that it will automatically run the tests and not have to preload rails.

Ah, much faster feedback but keeping the terminal window open is kind of a drag. Let's fix that!

Notifications

Let's provide notification pop ups whenever tests are run. This will allow us to keep the terminal window in the background and not have to even look at it unless we have test failures! Keeping our focus in the code requires less context switching and it's easy to setup!

I'm going to assume that you have a Mac and have brew installed. Install terminal-notifier

brew install terminal-notifier

Then, in your Gemfile, add the following gem:

group :development do
  gem 'terminal-notifier-guard', '~> 1.6.1'
end
bundle install

The last step is integrate terminal_notifier with guard. In your Guardfile, add the following line at the end of the file:

notification :terminal_notifier

Restart Guard if you had it running. After Guard runs your tests, you should receive a notification in the upper right hand corner saying all your tests passed!

Congrats! This TDD flow has helped me stay focus on the problem at hand and not worry about constantly checking the terminal, waiting for tests to run.

Thursday, July 7, 2016

Mock Server

Sometimes you need to mock out a web endpoint and Mock Server is a good tool to do this. There are many common uses cases for this including:
  • Working in conjunction with a 3rd party and the endpoint isn’t ready yet
  • Endpoint may not be reliable
  • Testing purposes
The advantages I saw of Mock Server versus others I looked at were:
  • Ability to register endpoints dynamically
  • Ruby library - Relatively simple to setup

Setup

Mock Server has two parts:
  • The Server - which can be downloaded from here as a jar
  • The client, which is available in Java, JavaScript, and Ruby. For this post, I’m going to focus on the Ruby gem.

Starting up Server

Run the following from the command line:
java -jar <path to mockserver-netty-3.10.4-jar-with-dependencies.jar> --serverPort 8080

Setup the client

Create a Gemfile and add the following:

gem ruby source: 'http://rubygems.org'
gem 'mockserver-client' 

Run bundle install

Create Expectations

Now that we are setup, in order to setup a mocked endpoint, an expectation needs to be created and registered with the Mock Server. Let’s setup a simple ‘GET’ endpoint for illustration.

Get Expectation

First, we’ll setup a class called ExpecationGenerator:
require 'mockserver-client'

class ExpectationGenerator
  include MockServer
  include MockServer::Model::DSL

  def initialize(server_port)
    @client = MockServerClient.new('localhost', server_port)
  end

  def simple_get_expectation
    expectation = expectation do |expectation|
      expectation.request do |request|
        request.method = 'GET'
        request.path = '/simple-get'
      end

      expectation.response do |response|
        response.status_code = 200
        response.body = "Success"
      end
    end

    expectation.times = unlimited() #once()
    @client.register(expectation)
  end
end

mock_server = ExpectationGenerator.new(8080)
mock_server.simple_get_expectation

Code highlights:
  • Setup a class that includes MockServer and the MockServer::Model::DSL
  • Initialize a MockServerClient with the server and port of where your mock server is running
  • Setup the expectation request and response for a ‘GET’ method
    • request.method can be set to ‘GET’, ‘POST’, etc.
    • request.path is the path to mock out
    • response.status_code returns the HTTP status code of the mocked method
    • response.body returns the body to be returned by the endpoint
      • expectation.times can be set to unlimited, as in our example. It can also be set to once(), twice(), etc. Once this endpoint gets hit n number of times, then it becomes invalid and will result in a 404.
  • last piece is registering the endpoint with the client
  • Now that we have the class setup, we need to instantiate it with the mock_server variable

Running the example

  • Start the mock server:
    • java -jar <path to mockserver-netty-3.10.4-jar-with-dependencies.jar> --serverPort 8080
  • Call the expectations.rb file
    • ruby expectations.rb

Prove that it works

  • Open up a browser, type in http://localhost:8080/simple-get and it should return “Success”
This post serves as an introduction to mock server. It’s capable of much more. I would encourage checking out Mock Server

Monday, May 16, 2016

5 Characteristics of a Great Product Owner

The Product Owner is a crucial part of the agile team.  I've had the experience of working with a number of different Product Owners.  This role is critical in leading the team in prioritizing work and having a vision for the product and knowing what to build.  Here are 5 characteristics I've observed in great Product Owners:

Trustworthy Partner

Trust is the number one characteristic of a making a great team.  The team that can trust each other can go far.  The Product Owner plays a crucial part in this.  This person needs to be able to trust the team to identify things they need and also for the team to speak up if there's issues/risks along the way.

A great PO will work through issues and partner with the team to come up with alternative solutions.  If a feature is much more effort than originally thought, is there an easier way we can get similar functionality, with less cost, that would still enable a useful user experience?  Being willing to negotiate and partner with the team to ensure the simplest, most cost effective solutions are being created.

This partnership means being actively participating in the scrum ceremonies: prioritizing stories, stand up, and retrospectives but constantly being available, ideally in the team room.  Team members may not constantly have questions to ask but recognize that once they do have questions, often times they are blockers until they get answers.  Blockers are expensive.  Having that conversation and answering questions sooner than later, keeps the team moving and delivering value.

Power 

A great PO has the power to make decisions.  He/she has autonomy to make decisions regarding the product.  The PO is the product ambassador, being tuned to the goals and users of this software solution and must be trusted from outside the team room to make decisions.  The more powerless the PO, the greater the time to market.


Pain

A great PO is experiencing pain.  If pain is not being experienced, what value is the software?  Pain tends to be a motivator to get things done.  A mix of power and pain can really be an asset to an agile team who strives to deliver value quickly and iteratively.

Product Focused

A great PO has the product's best interest in mind.  He/she is product driven, a solid idea of what the team needs to build, and what value each story has and prioritizes according to the biggest value first.  While they are a critical role in the process both inside and outside the team, the product is of first importance.

Political Prowess

Navigating the corporate landscape and getting things done fast on behalf of the team.  If the team needs a tool to make them faster or needs approval, the Product Owner knows how to navigate and get that tool or approval fast so the team can keep moving and delivering value at an optimum pace.

In your experience, what makes a great Product Owner?