I love TDD

Dans l’article précédent « Utiliser Chef #3 – TTD ! 1/2 « , je vous ai promis d’avoir rapidement la suite. Voilà chose faite !

Nous avons vu le principe du TDD. Dans ce qui va suivre, nous allons écrire les tests puis la recette Chef.

Et tout ça en mode TDD.

Hop hop hop, maintenant utilisons tout ce que nous avons installé :

% bundle exec foodcritic cookbooks/nginx_unicorn
FC008: Generated cookbook metadata needs updating: cookbooks/nginx_unicorn/metadata.rb:2
FC008: Generated cookbook metadata needs updating: cookbooks/nginx_unicorn/metadata.rb:3

Foodcritic en bon critique culinaire vous remonte les problèmes grossiers que vous avez dans votre recette Chef.

Allons corriger tout ça :

% cd cookbooks/nginx_unicorn
% vi metadata.rb # Ou l'éditeur texte que vous voulez

Le but est de remplacer les informations par rapport à votre recette Chef :

name 'nginx_unicorn'
maintainer 'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license 'All rights reserved'
description 'Installs/Configures nginx_unicorn'
long_description IO.read(
File.join(File.dirname(__FILE__), 'README.md'))
version '0.1.0'

Par :

name 'nginx_unicorn'
maintainer 'Ledez Incorporated'
maintainer_email 'yes-I-love@spam.com'
license 'All rights reserved'
description 'Installs/Configures nginx & unicorn'
long_description IO.read(File.join(File.dirname(__FILE__), 'README.md'))
version '0.1.0'

Au passage éditez le fichier README.md

Maintenant le critique gastronomique semble content de notre repas :

% bundle exec foodcritic .

La commande ne doit rien retourner. Dans le cas contraire, vous avez un problème.

TDD ! TDD ! TDD ! :

Les commandes suivantes vont créer la coquille vide pour faire des tests unitaires avec chef-spec puis les lancer :

% bundle exec knife cookbook create_specs nginx_unicorn
** Creating specs for cookbook: nginx_unicorn
% bundle exec rspec --color
*

Pending:
nginx_unicorn::default should do something
# Your recipe examples go here.
# ./spec/default_spec.rb:5

Finished in 0.00045 seconds
1 example, 0 failures, 1 pending

Donc en gros un exemple qui est considéré comme « en cours ». Ça se confirme en regardant le fichier tout nouvellement générer (spec/default_spec.rb) :

require 'chefspec'

describe 'nginx_unicorn::default' do
  let (:chef_run) { ChefSpec::ChefRunner.new.converge 'nginx_unicorn::default' }
  it 'should do something' do
    pending 'Your recipe examples go here.'
  end
end

Nous allons faire notre premier test (on remplace le bloc it…end) :

it 'should deploy nginx' do
  runner = expect(chef_run)

  runner.to install_package "nginx"
end

Et on lance le test :

% bundle exec rspec --color
Compiling Cookbooks...
F

Failures:

1) nginx_unicorn::default should deploy nginx
Failure/Error: runner.to install_package "nginx"
No package resource named 'nginx' with action :install found.
# ./spec/default_spec.rb:8:in `block (2 levels) in '

Finished in 0.00393 seconds
1 example, 1 failure

Failed examples:

rspec ./spec/default_spec.rb:5 # nginx_unicorn::default should deploy nginx

C’est rouge ! Notre test ne marche pas ! Et ben c’est une bonne nouvelle. Nous allons maintenant modifier ce qu’il faut dans Chef pour que ça passe vert (en éditant le fichier recipes/default.rb) :

#
# Cookbook Name:: nginx_unicorn
# Recipe:: default
#
# Copyright 2013, Ledez Incorporated
#
# All rights reserved - Do Not Redistribute
#
package "nginx" do
  action :install
end

Et on relance maintenant le test :

% bundle exec rspec --color
Compiling Cookbooks...
.

Finished in 0.00429 seconds
1 example, 0 failures

Vous voyez ça vient vite :)

Vous pouvez éditer vos fichiers en parralléle, avec vim c’est comme ça :

% vim -o recipes/default.rb spec/default_spec.rb

Sauf que relancer les tests toutes les 30s, ça va vite vous saouler. En tout cas moi oui :) J’utilise donc guard :

% bundle exec guard init
23:25:01 - INFO - Writing new Guardfile to /Users/nico/Devs/Ruby/chef/demo/cookbooks/nginx_unicorn/Guardfile
23:25:01 - INFO - rspec guard added to Guardfile, feel free to edit it

On vire les exemples qui ne servent à rien (Rails, Capybara et Turnip) dans le fichier Guardfile :

# A sample Guardfile
# More info at https://github.com/guard/guard#readme

guard :rspec, :cli => '--color --format doc' do
  watch(%r{^spec/.+_spec\.rb$})
  watch(%r{^recipes/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
  watch('spec/spec_helper.rb') { "spec" }
end

Au passage, on ajoute des paramètres pour le la sortie de rspec soit en couleur. C’est tout bête, mais un vert vert et un rouge rouge c’est plus rapidement vu :) vous avez noté aussi les changements du côté « lib » à remplacer par recipes. Car à la base rspec sert à tester du code Ruby. Vous lancez tout ça avec :

% bundle exec guard
23:35:56 - INFO - Guard uses Growl to send notifications.
23:35:56 - INFO - Guard uses TerminalTitle to send notifications.
23:35:56 - INFO - Guard::RSpec is running
23:35:56 - INFO - Guard is now watching at '/Users/nico/Devs/Ruby/chef/demo/cookbooks/nginx_unicorn'
[1] guard(main)>

Maintenant, à chaque modification dans un fichier le test correspondant est relancé. Essayez, vous allez vite comprendre.

A partir de maintenant, continuez de même « Test rouge » -> « Code simple vert » -> « Refactoring » -> passez par la case départ sans prendre les 20000 Euros. Et pensez à faire des commit réguliers :)

EDIT: J’ai oublié de mettre à jours le repository Github