José Valim - Remarkable 3.0 - KRUG - 07apr2009

56
José Valim 2009 José Valim http://plataformatec.com.br http://josevalim.blogspot.com [email protected] How do I test my applications?

description

My presentation about Remarkable 3.0, discussing also about tests in general.

Transcript of José Valim - Remarkable 3.0 - KRUG - 07apr2009

Page 1: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

José Valimhttp://plataformatec.com.br

http://[email protected]

How do I test my applications?

Page 2: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Who am I?

• Brazilian, 22-years-old, Master of Science in Engineering, Italy;

• Started with Ruby and Rails 2 years ago;

• Gems/plugin developer (Remarkable, Inherited Resources, Rails footnotes, Simple form and counting);

• Rails core contributor (11 patches and counting).

Page 3: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How do I test my applications?

Page 4: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

You should ask it everyday during

breakfast.

Page 5: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Or at least before each project.

Page 6: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

You might also want to know why do you test.

Page 7: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Or even why you should not test.

Page 8: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

What I already heard…

Page 9: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

What I already heard…

Page 10: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

A few reasons to test

• Ensure that everything works;

• Tests as documentation;

• Leads you to write better code.

Page 11: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

A few reasons NOT to test

I wrote it, then it works (yes, I heard it!);

Trust other people code. Should I test a has_one or a validates_presence_of in my models?

• Ensure that everything works

Page 12: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

A few reasons NOT to test

Your code should document itself;

• Tests as documentation

• Leads you to write better code

People spend more time writing tests than writing the code, which is what really matters.

Page 13: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Don’t judge.

Page 14: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Think.

Page 15: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How do I test?

• Waterfall? TDD? BDD?

• Test::Unit? Rspec?

• Isolation? Integration? Cucumber?

• Time? Fast?

Page 16: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Test::Unit? Rspec?

• Test::Unit is faster and simpler;

• Rspec code is more readable, not that fast;

• Rspec is great if you want to use your tests as documentation/specification.

Page 17: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Integration? Isolation?

• Integration = Rails default approach

Unit test your models and functional tests with your controllers and views.

• Isolation = Rspec default approach

Each MVC layer is tested separately with mocks and stubs. Then use Cucumber to integrate those layers.

Page 18: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

My experience

• I finish my tasks and tests faster when working in the integration way;

• Mocks and stubs are hard to maintain (does it has to be this way?);

• Not sure if integration runs faster than isolation and vice-versa.

Page 19: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Simplifying tests!

Page 20: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Simplifying tests (in rspec)!

Page 21: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

To use the tool, you have to understand the reasons.

Page 22: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Why to test Rails validations?

• You have to write the tests first;

• Validations are one liner. Easy to add, easy to remove;

• Documentation/specification;

• I do it.

Page 23: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to test Rails validations?

• Test::Unit way:

class UserTest < Test::Unit

def test_user_not_valid_if_name_is_blank

user = User.create

assert user.invalid?

assert_equal :blank, user.errors[:name]

end

end

Page 24: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to test Rails validations?

• Rspec way:

describe User do

it “should not be valid if name is blank” do

user = User.create

user.should_not be_valid

user.errors[:name].should == :blank

end

end

Page 25: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to test Rails validations?

• Remarkable way:

describe User do it { should validate_presence_of(:name) } end

• Or:

describe User do should_validate_presence_of :name end

Page 26: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to test Rails validations?

• Remarkable way:

describe User do it { should validate_presence_of(:name) } end

• Or:

describe User do should_validate_presence_of :name end

Conversion from matchers to macros happens automatically on Remarkable

Page 27: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Remarkable ActiveRecord 2.x

• Matchers for all validations with all options;

• Matchers for all associations, few options supported;

• Named scopes and mass assignment matchers;

• Database matchers;

• Callback, instance and class method matchers.

Page 28: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Remarkable ActiveRecord 3.0

• Matchers for all validations with all options;

• Matchers for all associations, almost all options supported;

• Named scopes and mass assignment matchers;

• Database matchers;

• Callback, instance and class method matchers.

Page 29: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Why have isolation tests?

• Design option;

• You love cucumber;

• I do it sometimes, sometimes I don’t.

Page 30: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to isolate my controllers?

• Rspec way:

describe TasksController do describe “responding to #POST create” do it "exposes a newly created task as @task" do Task.should_receive(:new).with({'these' => 'params'}). and_return(mock_task(:save => true)) post :create, :task => {:these => 'params'} assigns[:task].should equal(mock_task) end

it "redirects to the created task" do Task.stub!(:new).and_return(mock_task(:save => true)) post :create, :task => {} response.should redirect_to(task_url(mock_task)) end end end

Page 31: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to isolate my controllers?

• Rspec way:

describe TasksController do describe “responding to #POST create” do it "exposes a newly created task as @task" do Task.should_receive(:new).with({'these' => 'params'}). and_return(mock_task(:save => true)) post :create, :task => {:these => 'params'} assigns[:task].should equal(mock_task) end

it "redirects to the created task" do Task.stub!(:new).and_return(mock_task(:save => true)) post :create, :task => {} response.should redirect_to(task_url(mock_task)) end end end

Page 32: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Problems with Rspec way

•It’s not readable. I have to read the stubs before reading the action.

it "redirects to the created task" do

Task.stub!(:new).and_return(mock_task(:save => true))

post :create, :task => {}

response.should redirect_to(task_url(mock_task))

end

Page 33: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Problems with Rspec way

• It’s not DRY. I have to write expectations (:should_receive) and stubs (:stub!).

Task.should_receive(:new).with({'these' => 'params'}).

and_return(mock_task(:save => true))

Task.stub!(:new).and_return(mock_task(:save => true))

Page 34: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to isolate my controllers?

• Remarkable 3.0 way:

describe TasksController do

describe :post => :create, :task => {:these => 'params'} do

expects :new, :on => Task,

:with => { :these => 'params' },

:returns => mock_task

should_assign_to :task, :with => mock_task

should_redirect_to { task_url(mock_task) }

end

end

Page 35: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to isolate my controllers?

• Remarkable 3.0 way:

describe TasksController do describe :post => :create, :task => {:these => 'params'} do expects :new, :on => Task, :with => { :these => 'params' }, :returns => mock_task

should_assign_to :task, :with => mock_task should_redirect_to { task_url(mock_task) } end end

Perform action using expectations (:should_receive)

Page 36: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to isolate my controllers?

• Remarkable 3.0 way:

describe TasksController do describe :post => :create, :task => {:these => 'params'} do expects :new, :on => Task, :with => { :these => 'params' }, :returns => mock_task

should_assign_to :task, :with => mock_task should_redirect_to { task_url(mock_task) } end end

Perform action using stubs (:stub!)

Page 37: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Why to speed up my tests?

Page 38: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

Why to speed up my tests?

Page 39: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?• Rspec way (one request per test = slow):

describe TasksController do describe “responding to #POST create” do it "exposes a newly created task as @task" do Task.should_receive(:new).with({'these' => 'params'}). and_return(mock_task(:save => true)) post :create, :task => {:these => 'params'} assigns[:task].should equal(mock_task) end

it "redirects to the created task" do Task.stub!(:new).and_return(mock_task(:save => true)) post :create, :task => {} response.should redirect_to(task_url(mock_task)) end end end

Page 40: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Terrible way (but fast):

describe TasksController do describe “responding to #POST create” do it “should assign to @task and redirect” do Task.should_receive(:new).with({'these'=>'params'}). and_return(mock_task(:save => true))

post :create, :task => {:these => 'params'}

assigns[:task].should equal(mock_task) response.should redirect_to(task_url(mock_task)) end end end

Page 41: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Rspec solution?

before(:all) do

# It does not work without tweaking

end

• Test::Unit solution?

Page 42: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Remarkable 3.0 way:

describe TasksController do

describe :post! => :create do

expects :new, :on => Task, :returns => mock_task

should_assign_to :task, :with => mock_task

should_redirect_to { task_url(mock_task) }

end

end

Page 43: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Remarkable 3.0 way:

describe TasksController do

describe :post! => :create do

expects :new, :on => Task, :returns => mock_task

should_assign_to :task, :with => mock_task

should_redirect_to { task_url(mock_task) }

end

end

BANG!

Page 44: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Remarkable 3.0 way:

describe TasksController do

describe :post! => :create, :task => {} do

should_assign_to :task, :with => mock_task

should_redirect_to { task_url(mock_task) }

end

endWorks without stubs and mocks too.

Page 45: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

How to speed up my tests?

• Remarkable 3.0 BANG way:

Experimental. But if you have any problem, just remove the bang!

Its core might be ported back to rspec.

Page 46: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

And for those who use tests as specification…

Page 47: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

And for those who use tests as specification…

• example/specs.rb

describe User do

should_validate_presence_of :name, :email

xshould_validate_presence_of :age

should_validate_length_of :name, :within => 3..40

should_validate_uniqueness_of :email, :case_sensitive => false

should_validate_numericality_of :age, :only_integer => true,

:greather_than_or_equal_to => 18, :allow_blank => true

end

Page 48: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

And for those who use tests as specification…

• ruby example/specs.rb –cfs en

Example disabled: require age to be set

User- should require name and email to be set- should ensure length of name is within 3..40 characters- should require unique values for email case insensitive- should ensure numericality of age allowing only integer values

and allowing blank values

Finished in 0.262418 seconds

Page 49: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

And for those who use tests as specification…

• ruby example/specs.rb –cfs pl

Przykład niepełnosprawny: wymagać podania wiek

Użytkownik

- powinien wymagać podania imię i e-mail

- powinien upewnienia co do ilości znaków imię pomiędzy 3..40

- powinien wymagać niepowtarzalnych wartości dla e-mail z brakiem

znaczenia wielkości liter

- powinien upewnienia o numeryczności wiek zezwalając tylko na całe

wartości i zezwalając pustą wartość

Finished in 0.255462 seconds

Page 50: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

And for those who use tests as specification…

• ruby example/specs.rb –cfs pl

Przykład niepełnosprawny: wymagać podania wiek

Użytkownik

- powinien wymagać podania imię i e-mail

- powinien upewnienia co do ilości znaków imię pomiędzy 3..40

- powinien wymagać niepowtarzalnych wartości dla e-mail z brakiem

znaczenia wielkości liter

- powinien upewnienia o numeryczności wiek zezwalając tylko na całe

wartości i zezwalając pustą wartość

Finished in 0.255462 seconds REMARKABLE 3.0

SPECS WITH I18N

Page 51: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

So Remarkable is…

• A framework for rspec matchers which provides automatic conversion to macros;

• Decouple matcher logic from content, using .yml files and providing I18n;

• Has a DSL and provides common helpers .

Page 52: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

So Remarkable is…

• Remarkable 3.0 is composed of:

Remarkable Remarkable ActiveRecord

Matchers and some I18n tweaks Remarkable Rails

Controller matchers Macro Stubs (:expects DSL)

Page 53: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

So Remarkable is…

• Remarkable 3.x will be composed of:

Remarkable Remarkable ActiveRecord Remarkable Rails Remarkable Datamapper? Remarkable Sequel?

Page 54: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

So Remarkable is…

• Remarkable 3.x will be composed of:

Remarkable Remarkable ActiveRecord Remarkable Rails Remarkable Datamapper? Remarkable Sequel?

VOLUNTEERS?

Page 55: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

When? Where?

• Remarkable 3.0 beta will be released mid April;

• Got get it on Github:http://github.com/carlosbrando/remarkable

• Follow my blog:http://josevalim.blogspot.com/

Page 56: José Valim - Remarkable 3.0 - KRUG - 07apr2009

José Valim 2009

José Valimhttp://plataformatec.com.br

http://[email protected]

?!