MacBook:~ xyz$ rails new webshop [...] MacBook:~ xyz$ cd webshop MacBook:webshop xyz$ rails generate scaffold user login_name first_name last_name birthday:date [...] invoke test_unit create test/unit/user_test.rb create test/fixtures/users.yml [...] invoke test_unit create test/functional/users_controller_test.rb invoke helper create app/helpers/users_helper.rb invoke test_unit create test/unit/helpers/users_helper_test.rb [...] MacBook:webshop xyz$ rake db:migrate [...] MacBook:webshop xyz$
test
im
Dateinamen zu erkennen).MacBook:webshop xyz$ rake test
Run options:
# Running tests:
Finished tests in 0.003920s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Run options:
# Running tests:
.......
Finished tests in 0.223761s, 31.2834 tests/s, 44.6905 assertions/s.
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
7 tests, 10 assertions, 0 failures, 0 errors,
0 skips
“ sieht gut aus. Per Default läuft ein Test in einem
Standard-Scaffold korrekt durch.app/models/user.rb
und
fügen ein paar Validierungen (falls diese nicht ganz klar sind, bitte
Abschnitt 4.15, „Validierung
(Validation)“ lesen) ein:class User < ActiveRecord::Base attr_accessible :birthday, :first_name, :last_name, :login_name validates :login_name, :presence => true, :format => { :with => /^.*(?=.*[\-_.]).*$/, :message => "must include at least one of the special characters -_." } validates :last_name, :presence => true end
MacBook:webshop xyz$ rake test
Run options:
# Running tests:
Finished tests in 0.004409s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Run options:
# Running tests:
F.....F
Finished tests in 0.277867s, 25.1919 tests/s, 32.3896 assertions/s.
1) Failure:
test_should_create_user(UsersControllerTest) [/Users/xyz/webshop/test/functional/users_controller_test.rb:20]:
"User.count" didn't change by 1.
<3> expected but was
<2>.
2) Failure:
test_should_update_user(UsersControllerTest) [/Users/xyz/webshop/test/functional/users_controller_test.rb:39]:
Expected response to be a <:redirect>, but was <200>
7 tests, 9 assertions, 2 failures, 0 errors, 0 skips
Errors running test:functionals! #<RuntimeError: Command failed with status (2): [/Users/xyz/.rvm/rubies/ruby-1.9.3-p194/bin...]>
MacBook:webshop xyz$
2 failures
“. Der Fehler
passiert beim „should create user
“ und beim
„should update user
“. Die Erklärung hierfür liegt in
unserer Validierung. Die vom Scaffold Generator angelegten Beispieldaten
sind beim ersten rake test (ohne Validierung)
durchgelaufen. Erst beim zweiten Durchlauf (mit Validierung) gab es die
Fehler.test/fixtures/
angelegt. Schauen wir uns die
Beispieldaten für User
in der Datei
test/fixtures/users.yml
an:# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html one: login_name: MyString first_name: MyString last_name: MyString birthday: 2012-05-29 two: login_name: MyString first_name: MyString last_name: MyString birthday: 2012-05-29
login_name
braucht
mindestens ein "-_."-Sonderzeichen. Ändern wir login_name
in
test/fixtures/users.yml
entsprechend
ab:# Read about fixtures at http://api.rubyonrails.org/classes/Fixtures.html one: login_name: My-String firstname: MyString lastname: MyString birthday: 1970-01-01 two: login_name: My-String firstname: MyString lastname: MyString birthday: 1970-01-01
MacBook:webshop xyz$ rake test
Run options:
# Running tests:
Finished tests in 0.003977s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Run options:
# Running tests:
.......
Finished tests in 0.204496s, 34.2305 tests/s, 48.9007 assertions/s.
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
test/fixtures/users.yml
valide Daten stehen müssen,
damit der mit Scaffold erstellte Standard-Test durchläuft. Aber auch nicht
mehr. Nachfolgend ändern wir die
test/fixtures/users.yml
auf ein Minimum (wir brauchen
z. B. keinen first_name
) und mit für Menschen leichter
lesbaren Daten ab:one: login_name: horst.meier last_name: Meier two: login_name: emil.stein last_name: Stein
MacBook:webshop xyz$ rake test
Run options:
# Running tests:
Finished tests in 0.004234s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
Run options:
# Running tests:
.......
Finished tests in 0.202971s, 34.4877 tests/s, 49.2681 assertions/s.
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
uniqueness
in der
Validierung benutzt, muss man dies beim Test im Hinterkopf
behalten.1) Failure: test_should_create_user(UsersControllerTest) [/Users/xyz/webshop/test/functional/users_controller_test.rb:20]: "User.count" didn't change by 1. <3> expected but was <2>. 7 tests, 9 assertions, 1 failures, 0 errors, 0 skips Errors running test:functionals! #<RuntimeError: Command failed with status (1): [/Users/xyz/.rvm/rubies/ruby-1.9.3-p194/bin...]>
UsersControllerTest
konnte der User nicht angelegt
und nicht verändert werden. Die Controller-Tests befinden sich im
Verzeichnis test/functional/
. Schauen wir uns jetzt
die Datei test/functional/users_controller_test.rb
genau an:require 'test_helper' class UsersControllerTest < ActionController::TestCase setup do @user = users(:one) end test "should get index" do get :index assert_response :success assert_not_nil assigns(:users) end test "should get new" do get :new assert_response :success end test "should create user" do assert_difference('User.count') do post :create, user: { birthday: @user.birthday, first_name: @user.first_name, last_name: @user.last_name, login_name: @user.login_name } end assert_redirected_to user_path(assigns(:user)) end test "should show user" do get :show, id: @user assert_response :success end test "should get edit" do get :edit, id: @user assert_response :success end test "should update user" do put :update, id: @user, user: { birthday: @user.birthday, first_name: @user.first_name, last_name: @user.last_name, login_name: @user.login_name } assert_redirected_to user_path(assigns(:user)) end test "should destroy user" do assert_difference('User.count', -1) do delete :destroy, id: @user end assert_redirected_to users_path end end
setup
-Anweisung:
setup do @user = users(:one) end
@user
mit den Daten des
Eintrages one
aus der Datei
test/fixtures/users.yml
angelegt wird.
setup
ist ein vordefinierter Callback, der –
falls vorhanden – von Rails vor jedem Test gestartet wird. Das
Gegenstück zu setup
ist
teardown
. Ein teardown
wird – falls vorhanden – nach jedem Test automatisch
aufgerufen.config/database.yml
definiert. Auf die Test-Datenbank können Sie zu Debug-Zwecken mit
rails console test zugreifen.test "should get index" do get :index assert_response :success assert_not_nil assigns(:users) end
get :index
ruft die Seite
/users
auf. assert_response :success
bedeutet,
dass die Seite ausgeliefert wurde. Die Zeile assert_not_nil
assigns(:users)
stellt sicher, dass die Instanz-Variable
@users
vom Controller nicht mit dem Wert
nil
zum View gegeben wird (durch
setup
wurde ja sichergestellt, dass bereits ein
Eintrag in der Datenbank ist).[27]should create user
:test "should create user" do assert_difference('User.count') do post :create, user: { birthday: @user.birthday, first_name: @user.first_name, last_name: @user.last_name, login_name: @user.login_name } end assert_redirected_to user_path(assigns(:user)) end
assert_difference('User.count') do ... end
erwartet eine Veränderung durch den darin enthaltenen Code.
User.count
müsste am Anfang 1 ergeben und am Ende 2. Da wir
aber in der ersten test/fixtures/users.yml
-Variante
einen ungültigen Datensatz hatten, ergab User.count
vorher
und hinterher 0. 0 und nicht 1 am Anfang, weil auch das setup do
... end
nicht funktioniert haben kann.assert_redirected_to
user_path(assigns(:user))
überprüft, ob nach einem neu angelegten
Datensatz auch auf den entsprechenden View show
geleitet
wird.should update
user
:test "should update user" do put :update, id: @user, user: { birthday: @user.birthday, first_name: @user.first_name, last_name: @user.last_name, login_name: @user.login_name } assert_redirected_to user_path(assigns(:user)) end
id
des
@user
-Datensatzes mit den Attributen des
@user
-Datensatzes geupdatet werden. Danach soll auch
wieder der show
-View zu diesem Datensatz angezeigt werden.
Logischerweise ging dieser Test auch nicht, da a) der
@user
-Datensatz gar nicht in der Datenbank existierte
und b) er auch nicht geupdatet werden konnte, da er nicht valide
war.test/functional/
durchlaufen lassen.MacBook:webshop xyz$ rake test:functionals
Run options:
# Running tests:
.......
Finished tests in 0.205717s, 34.0273 tests/s, 48.6105 assertions/s.
7 tests, 10 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
app/models/user.rb
eingetragen haben, sind Unit
Tests besser geeignet. Diese testen nicht wie die Functional Tests die
Arbeit des Controllers, sondern nur das Model.test/unit/
ausgeführt.test/unit/
. Ein Blick in die Datei
test/unit/user_test.rb
ist aber
ernüchternd:require 'test_helper' class UserTest < ActiveSupport::TestCase # test "the truth" do # assert true # end end
MacBook:webshop xyz$ rake test:units
Run options:
# Running tests:
Finished tests in 0.004657s, 0.0000 tests/s, 0.0000 assertions/s.
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
test "eine Behauptung
" do assertetwas_ist_true_oder_false
end
assert
bedeutet in diesem Kontext behaupten oder feststellen. Es
wird also eine Behauptung aufgestellt. Wenn diese Behauptung
true
(wahr) ist, dann läuft der Test durch und alles ist
okay. Wenn diese Behauptung false
(falsch) ist, schlägt der
Test fehl und wir haben einen Fehler im Programm (die Ausgabe des
Fehlers können Sie am Ende der assert-Zeile als String angeben).assert
-Varianten gibt. Hier einige
Beispiele:assert( boolean
,
[msg]
)
assert_equal( obj1
,
obj2
,
[msg]
)
assert_not_equal( obj1
,
obj2
,
[msg]
)
assert_same( obj1
,
obj2
,
[msg]
)
assert_not_same( obj1
,
obj2
,
[msg]
)
assert_nil( obj
,
[msg]
)
assert_not_nil( obj
,
[msg]
)
assert_match( regexp
,
string
,
[msg]
)
assert_no_match( regexp
,
string
,
[msg]
)
test/unit/user_test.rb
mit Leben:require 'test_helper'
class UserTest < ActiveSupport::TestCase
test 'an empty user is not valid' do
assert !User.new.valid?, 'Saved an empty user.'
end
end
User
, der keine Daten enthält, valide ist. Da
assert
nur auf true
reagiert, habe ich vor
User.new.valid?
ein „!
“ gesetzt, um aus dem
false
ein true
zu machen, denn ein leerer User
kann ja nicht valide sein.MacBook:webshop xyz$ rake test:units
Run options:
# Running tests:
.
Finished tests in 0.081926s, 12.2061 tests/s, 12.2061 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
test/fixtures/users.yml
auch valide
sind:require 'test_helper'
class UserTest < ActiveSupport::TestCase
test 'an empty user is not valid' do
assert !User.new.valid?, 'Saved an empty user.'
end
test "the two fixture users are valid" do
assert User.new(last_name: users(:one).last_name, login_name: users(:one).login_name ).valid?, 'First fixture is not valid.'
assert User.new(last_name: users(:two).last_name, login_name: users(:two).login_name ).valid?, 'Second fixture is not valid.'
end
end
MacBook:webshop xyz$ rake test:units
Run options:
# Running tests:
..
Finished tests in 0.090001s, 22.2220 tests/s, 33.3330 assertions/s.
2 tests, 3 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
login_name
-Varianten ein:require 'test_helper'
class UserTest < ActiveSupport::TestCase
test 'an empty user is not valid' do
assert !User.new.valid?, 'Saved an empty user.'
end
test "the two fixture users are valid" do
assert User.new(last_name: users(:one).last_name, login_name: users(:one).login_name ).valid?, 'First fixture is not valid.'
assert User.new(last_name: users(:two).last_name, login_name: users(:two).login_name ).valid?, 'Second fixture is not valid.'
end
[
'hans.meier',
'hans-meier',
'h-meier',
'h_meier',
'h.meier2',
].each do |valid_login_name|
test "the login_name '#{valid_login_name}' is valid" do
assert User.new(last_name: users(:one).last_name, login_name: valid_login_name ).valid?, "login_name '#{valid_login_name}' is not valid."
end
end
end
MacBook:webshop xyz$ rake test:units
Run options:
# Running tests:
.......
Finished tests in 0.090630s, 77.2371 tests/s, 88.2710 assertions/s.
7 tests, 8 assertions, 0 failures, 0 errors, 0 skips
MacBook:webshop xyz$
[27] Dabei wird hier das Symbol :users
genommen,
um sicherzustellen, dass @users
in der zu
testenden Controller-Klasse und nicht @users
in
der Test-Klasse selbst genommen wird.