Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
vajradog committed Aug 5, 2014
0 parents commit 43f0fc4
Show file tree
Hide file tree
Showing 66 changed files with 1,095 additions and 0 deletions.
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
#
# If you find yourself ignoring temporary files generated by your text editor
# or operating system, you probably want to add a global ignore instead:
# git config --global core.excludesfile '~/.gitignore_global'

# Ignore bundler config.
/.bundle

# Ignore the default SQLite database.
/db/*.sqlite3
/db/*.sqlite3-journal

# Ignore all logfiles and tempfiles.
/log/*.log
/tmp
17 changes: 17 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
source 'https://rubygems.org'
gem 'rails', '4.0.2'
gem 'sqlite3'
gem 'sass-rails', '~> 4.0.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.0.0'
gem 'jquery-rails'
gem 'turbolinks'
gem 'jbuilder', '~> 1.2'

group :doc do
gem 'sdoc', require: false
end

group :test, :development do
gem 'mocha'
end
122 changes: 122 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
GEM
remote: https://rubygems.org/
specs:
actionmailer (4.0.2)
actionpack (= 4.0.2)
mail (~> 2.5.4)
actionpack (4.0.2)
activesupport (= 4.0.2)
builder (~> 3.1.0)
erubis (~> 2.7.0)
rack (~> 1.5.2)
rack-test (~> 0.6.2)
activemodel (4.0.2)
activesupport (= 4.0.2)
builder (~> 3.1.0)
activerecord (4.0.2)
activemodel (= 4.0.2)
activerecord-deprecated_finders (~> 1.0.2)
activesupport (= 4.0.2)
arel (~> 4.0.0)
activerecord-deprecated_finders (1.0.3)
activesupport (4.0.2)
i18n (~> 0.6, >= 0.6.4)
minitest (~> 4.2)
multi_json (~> 1.3)
thread_safe (~> 0.1)
tzinfo (~> 0.3.37)
arel (4.0.2)
builder (3.1.4)
coffee-rails (4.0.1)
coffee-script (>= 2.2.0)
railties (>= 4.0.0, < 5.0)
coffee-script (2.3.0)
coffee-script-source
execjs
coffee-script-source (1.7.1)
erubis (2.7.0)
execjs (2.2.1)
hike (1.2.3)
i18n (0.6.11)
jbuilder (1.5.3)
activesupport (>= 3.0.0)
multi_json (>= 1.2.0)
jquery-rails (3.1.1)
railties (>= 3.0, < 5.0)
thor (>= 0.14, < 2.0)
json (1.8.1)
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
metaclass (0.0.4)
mime-types (1.25.1)
minitest (4.7.5)
mocha (1.1.0)
metaclass (~> 0.0.1)
multi_json (1.10.1)
polyglot (0.3.5)
rack (1.5.2)
rack-test (0.6.2)
rack (>= 1.0)
rails (4.0.2)
actionmailer (= 4.0.2)
actionpack (= 4.0.2)
activerecord (= 4.0.2)
activesupport (= 4.0.2)
bundler (>= 1.3.0, < 2.0)
railties (= 4.0.2)
sprockets-rails (~> 2.0.0)
railties (4.0.2)
actionpack (= 4.0.2)
activesupport (= 4.0.2)
rake (>= 0.8.7)
thor (>= 0.18.1, < 2.0)
rake (10.3.2)
rdoc (4.1.1)
json (~> 1.4)
sass (3.2.19)
sass-rails (4.0.3)
railties (>= 4.0.0, < 5.0)
sass (~> 3.2.0)
sprockets (~> 2.8, <= 2.11.0)
sprockets-rails (~> 2.0)
sdoc (0.4.0)
json (~> 1.8)
rdoc (~> 4.0, < 5.0)
sprockets (2.11.0)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
sprockets-rails (2.0.1)
actionpack (>= 3.0)
activesupport (>= 3.0)
sprockets (~> 2.8)
sqlite3 (1.3.9)
thor (0.19.1)
thread_safe (0.3.4)
tilt (1.4.1)
treetop (1.4.15)
polyglot
polyglot (>= 0.3.1)
turbolinks (2.2.2)
coffee-rails
tzinfo (0.3.40)
uglifier (2.5.3)
execjs (>= 0.3.0)
json (>= 1.8.0)

PLATFORMS
ruby

DEPENDENCIES
coffee-rails (~> 4.0.0)
jbuilder (~> 1.2)
jquery-rails
mocha
rails (= 4.0.2)
sass-rails (~> 4.0.0)
sdoc
sqlite3
turbolinks
uglifier (>= 1.3.0)
221 changes: 221 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
Based on Andrzej Krzywda's [post](http://andrzejonsoftware.blogspot.com/2007/05/15-tdd-steps-to-create-rails.html), *"15 TDD steps to create a Rails Application"* which is recommended in the Rails Guide *[A guide to testing rails application](http://guides.rubyonrails.org/testing.html)*. The original post was published in May, 2007 and some codes have since deprecated. I have attempted to update the tutorial here in the hope that it may benefit many people like me.

This tutorial takes the TDD approach in building a simple word-learning web application, it displays a random word object (with its Polish translation) from the database. Everytime we refresh, we see a different word. Again, for the original post please click [here](http://andrzejonsoftware.blogspot.com/2007/05/15-tdd-steps-to-create-rails.html).

Let's begin
----------
### 1. Create a new Rails application

$ rails new my_app

$ cd my_app

Run tests with 'rake test'. It fails due to missing database configuration.

### 2. Prepare your database
$ rake db:migrate

$ rake test *~> should now run fine*

### 3. Create a Word class with corresponding unit test
$ rails g model Word

### 4. Write a unit test for the Word class.
Edit the test/models/word_test.rb

```
test 'word is in both English and Polish' do
word = Word.new eng:'never', pl:'nigdy'
assert_equal 'never', word.eng
assert_equal 'nigdy', word.pl
end
```
$ rake test *~> should now fail due to missing columns in words table*

### 5. Add columns to your table

$ rails g migration add_eng_and_pl_to_words

From your db/migrate folder open the new migration file you just created and add the following columns like so:

```
class AddEngAndPlToWords < ActiveRecord::Migration
def change
add_column :words, :eng, :string
add_column :words, :pl, :string
end
end
```
$ rake db:migrate *~> to prepare the schema so we can add create some words*

From your rails console ($ rails console)

$ Word.create(eng:'yes', pl:'tak')

$ Word.create(eng:'no', pl:'nie')

$ Word.create(eng:'everything', pl:'wszystko')

This will create the three words with its Polish translation.

$ rake test *~> should now succeed with the following:*

*'1 tests, 2 assertions, 0 failures, 0 errors'*

### 6. Fixtures and test for word.random.

Edit word_test.rb again. The test/models/word_test.rb file should now look like this:

```
require 'test_helper'
class WordTest < ActiveSupport::TestCase
fixtures :words
test 'word is in both English and Polish' do
word = Word.new eng:'never', pl:'nigdy'
assert_equal 'never', word.eng
assert_equal 'nigdy', word.pl
end
test 'show random words' do
results = []
10.times {results << Word.random.eng}
assert results.include?("yes")
end
end
```

Edit the words.yml file (in the fixtures folder) to look like this:

```
---
false:
eng: "no"
id: 2
pl: nie
true:
eng: "yes"
id: 1
pl: tak
```

Be careful with the spacing. YML files are like crazy annoying people, they'll yell at you if you miss a space. Head over to <http://yamllint.com/> and validate your yaml if unsure or learn more here: <http://ess.khhq.net/wiki/YAML_Tutorial>

In the word_test.rb file, notice the "fixtures :words", the words.yml file will now be loaded to the test database before every run of tests.

### 7. Implement the Word.random method
In your app/models/word.rb implement the word.random method like so:

```
class Word < ActiveRecord::Base
def self.random
all = Word.all
all[rand(all.size)]
end
end
```

### 8. Generate the Words controller with a 'learn' action
$ rails g controller Words learn

### 9. Write a test for the learn method.
Just as there is one-to-one ratio between unit tests and models, so there is between functional tests and controllers. The Controller's responsibility is to retrieve objects from the Model layer and pass them to the View. Let's test the View part first. We use the 'assigns' collection which contains all the objects passed to the View.

In the test/controllers/words_controller_test.rb

```
require 'test_helper'
class WordsControllerTest < ActionController::TestCase
test "learn method passes a random word" do
get 'learn'
assert_kind_of Word, assigns('word')
end
end
```
$ rake test

### 10. Make the Test Pass

In your app/controllers/words_controller.rb

```
class WordsController < ApplicationController
def learn
@word = Word.new
end
end
```

### 11. Write more tests in the words_controller_test
How can we test that the controller uses the Word.random method? We don't want to duplicate the tests for the Word.random method. Mocks to the rescue! We will only test that the controller calls the Word.random method. The returned value will be faked with a prepared word. Let's install the mocha framework.

In your Gemfile

```
group :test, :development do
gem 'mocha'
end
```
At bottom of test_helper.rb (or at least after `require 'rails/test_help') add:

`require 'mocha/mini_test'`

We can now use 'expects' and 'returns' methods. 'expects' is used for setting an expectation on an object or a class. In this case we expect that the 'random' method will be called. We also set a return value by using 'returns' method. Setting a return value means faking (stubbing) the real method. The real Word.random won't be called. If an expectation isn't met; the test fails.

```
require 'test_helper'
class WordsControllerTest < ActionController::TestCase
test "learn method passes a random word" do
random_word = Word.new
Word.expects(:random).returns(random_word)
get 'learn'
assert_equal random_word, assigns('word')
end
end
```
$ rake test *~> should now fail*

### 12. Rewrite the implementation
Edit words_controller.rb

```
def learn
@word = Word.random
end
```

### 13. Test that a word is displayed: Extend the existing test with assert_tag calls.
Edit words_controller_test.rb

```
test "learn method passes a random word" do
random_word = Word.new(pl:'czesc', eng:'hello')
Word.expects(:random).returns(random_word)
get 'learn'
assert_equal random_word, assigns('word')
assert_tag tag:'div', child: /czesc/
assert_tag tag:'div', child: /hello/
end
```

### 14. Implement the view
In app/views/words/learn.html.erb

```<div>
<%= @word.eng %>
<%= @word.pl %>
</div>
```
### 15. Manual testing
$ rails server

Go to http://localhost:3000/words/learn
Refresh several times to see different words.

Related articles:
[Some more TDD steps with Rails Testing](http://andrzejonsoftware.blogspot.com/2007/05/and-some-more-tdd-steps-with-rails.html), [Rails controllers with mock objects](http://andrzejonsoftware.blogspot.com/2007/06/testing-rails-controllers-with-mock.html) If you want to read more about testing in Rails go to the [Guide To Testing The Rails.](http://manuals.rubyonrails.com/read/book/5)
6 changes: 6 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Add your own tasks in files placed in lib/tasks ending in .rake,
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.

require File.expand_path('../config/application', __FILE__)

MyApp::Application.load_tasks
Empty file added app/assets/images/.keep
Empty file.
Loading

0 comments on commit 43f0fc4

Please sign in to comment.