test context arrangement recipebook
DESCRIPTION
TRANSCRIPT
![Page 1: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/1.jpg)
5 years know-how of
RSpec drivenRails app. development
MOROHASHI Kyosuke(@moro)
![Page 2: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/2.jpg)
Kyosuke MOROHASHI
✓ http://twitter.com/moro
✓ http://github.com/moro
✓ Eiwa System Management, Inc.
![Page 3: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/3.jpg)
![Page 5: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/5.jpg)
http://tatsu-zine.com/books/cuke
RubyKaigi
special price
40% off
![Page 6: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/6.jpg)
http://amzn.to/rails3recipebook
Available
@Junku-Do
RubyKaigi
![Page 7: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/7.jpg)
http://www.junkudo.co.jp/tenpo/evtalk.html#20110721ikebukuro
![Page 8: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/8.jpg)
5 years know-how of
RSpec drivenRails app. development
MOROHASHI Kyosuke(@moro)
![Page 9: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/9.jpg)
諸橋 恭介
3の技
レシピブック
Test Context Arrangement
![Page 10: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/10.jpg)
✓What test should I write first?
✓ Write model unit test.✓I began model test,but it’s difficult to setup data!!
✓ Use multi strategies for multi types of data.
✓It seems good but less DRY. Is there any idea?
✓ Share your testing context.
I’ll talk about.
![Page 11: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/11.jpg)
Probl
em
What test should
I write first?
![Page 12: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/12.jpg)
Solu
tion
Write Modelunit test.
![Page 13: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/13.jpg)
Skinny ControllersFat Models
People say
![Page 15: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/15.jpg)
#64 2011-07-18 12:00@ねりぶん集会室
http://twitter.com/railstokyo
![Page 16: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/16.jpg)
RubyKaigi
special price
40% off
http://tatsu-zine.com/books/cuke
Use Cucumber(or other end-to-end testing)
to cover controller, views and more.
![Page 17: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/17.jpg)
Model unit test
![Page 18: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/18.jpg)
Probl
em
Began model test, but it’s difficult to setup data!!
![Page 19: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/19.jpg)
events
courses
rooms periods
registrations
students
lessons
![Page 20: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/20.jpg)
Course-1 Course-2
Period-1
Period-2
Period-3
Period-4
Period-5
Lesson-1-1 Lesson-2-1
Lesson-1-2 Lesson-2-2
Lesson-1-3 Lesson-2-3
Lesson-1-4 Lesson-2-4
Lesson-1-5 Lesson-2-5
registration
![Page 21: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/21.jpg)
Course-1 Course-2
Period-1
Period-2
Period-3
Period-4
Period-5
Lesson-1-1 Lesson-2-1
Lesson-1-2 Lesson-2-2
Lesson-1-3 Lesson-2-3
Lesson-1-4 Lesson-2-4
Lesson-1-5 Lesson-2-5
registration
Student#subscribe(course_1)
![Page 22: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/22.jpg)
Course-1 Course-2
Period-1
Period-2
Period-3
Period-4
Period-5
Lesson-1-1 Lesson-2-1
Lesson-1-2 Lesson-2-2
Lesson-1-3 Lesson-2-3
Lesson-1-4 Lesson-2-4
Lesson-1-5 Lesson-2-5
registration
Student#register!(lesson_2_4)
![Page 23: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/23.jpg)
student.subscribe(course)
student.register!( @another_course.lessons[3])
![Page 24: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/24.jpg)
describe Student do let(:student) { Student.create(name: 'Alice') } before do event = Event.create(name: 'Camp') course = event.courses.create(name: 'Course-1') 5.times {¦i¦ course.lessons.create(name: "Lessson-#{i}") } student.subscribe(course)
@another_course = event.courses.create(name: 'Course-2') 5.times {¦i¦ @another_course.lessons.create(name: "NewLessson-#{i}") } student.register!(@another_course.lessons[3]) end its(:registering_lessons) do should include(@another_course.lessons[3]) endend
![Page 25: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/25.jpg)
describe Student do let(:student) { Student.create(name: 'Alice') } before do event = Event.create(name: 'Camp') course = event.courses.create(name: 'Course-1') 5.times {¦i¦ course.lessons.create(name: "Lessson-#{i}") } student.subscribe(course)
@another_course = event.courses.create(name: 'Course-2') 5.times {¦i¦ @another_course.lessons.create(name: "NewLessson-#{i}") } student.register!(@another_course.lessons[3]) end its(:registering_lessons) do should include(@another_course.lessons[3]) endend
![Page 26: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/26.jpg)
Solu
tion
Use multi strategies for multi types of data.
![Page 27: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/27.jpg)
✓ 3 types of data✓ 3 strategies
![Page 28: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/28.jpg)
✓ 3 types of data✓ 3 strategies
![Page 29: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/29.jpg)
✓Master data✓ Resource data✓ Event data
![Page 30: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/30.jpg)
✓ Created/updated rarely.✓e.g. rooms / periods.✓ Less dependencies to others.✓ Maintained by scaffold or so.
Mastar data
![Page 31: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/31.jpg)
✓Mainly created/updated data.
✓ Users themselves maintains this type of data.
Resource data
![Page 32: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/32.jpg)
✓ Represent relationship between resources.
✓ Used for has_many :through ‘s through table in Rails.
Event data
![Page 33: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/33.jpg)
✓ 3 types of data✓ 3 strategies
![Page 34: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/34.jpg)
✓ Fixture
✓ Fixture replacement
✓ before/setup block
![Page 36: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/36.jpg)
✓ good speed to be loaded.
✓ less maintainability.✓ less flexibility.
![Page 38: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/38.jpg)
✓ flexible.✓ powerful but
difficult to use correctly.
✓ slow to be loaded.
![Page 39: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/39.jpg)
Fabricator(:event) do name 'SummerCamp' courses!(count: 2) {¦e, i¦ Fabricate(:course, event: e) }end
Fabricator(:course) do name { sequence(:course_name) {¦i¦ "Course-#{i+1}" } } lessons!(count: 5) {¦course, i¦ Fabricate(:lesson, course: course, period_id: i) }end
Fabricator(:lesson) do name { sequence(:lesson_name) {¦i¦ "Lesson-#{i+1}" } } period_id 1 room_id 1end
![Page 40: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/40.jpg)
Which should we use rails-fixture or fixture replacement?
Use them both which suitable for the data.
![Page 41: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/41.jpg)
describe Student do let(:student) { Student.create(name: 'Alice') }
describe "#register" do
subject { student }
before do student.subscribe(course) student.register(another_course.lessons[3]) end
its(:registering_lessons) do
before/setup block
![Page 42: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/42.jpg)
✓ each run per test.✓ same speed with real data persistence.
✓ edit each of them to maintain.
![Page 43: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/43.jpg)
speed flexibilityin test
maintain-ability good for
fixture best wrong wrongMaster
data
fixturereplacements wrong good best
Resourcedata
before() good best
goodfor eachwrongfor all
Eventdata
![Page 44: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/44.jpg)
events
courses lessons
rooms periods
registrations
students
rooms periods
Master
events
courses lessons
studentsResource
registrations
Event
![Page 45: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/45.jpg)
describe Student do # fixture :all let(:student) { Fabricate(:student) }
describe "#register" do let(:event) { Fabricate(:event) } let(:course) { event.courses.first } let(:another_course) { event.courses.last }
subject { student }
before do student.subscribe(course) student.register!(another_course.lessons[3]) end
its(:registering_lessons) do should include(another_course.lessons[3]) end
![Page 46: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/46.jpg)
Solu
tion
Use multi strategies for multi types of data.
![Page 47: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/47.jpg)
type, strategy = if user.rarely_maitain?(data) [MastarData, :fixture] elsif data.through_table? [EventData, :before] else [ResourceData, :fixture_replacement] end
![Page 48: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/48.jpg)
✓ fixture✓ fixture replacement✓ before/setup block
Use them all which suitable for the data.
![Page 49: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/49.jpg)
Probl
em
It seems good but less DRY.Is there any idea?
![Page 50: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/50.jpg)
Course Students Count
Period-1
Period-2
Period-3
Period-4
Period-5
Lesson-1-1 2
Lesson-1-2 3
Lesson-1-3 3
Lesson-1-4 3
Lesson-1-5 2
Course#attendee_count
![Page 51: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/51.jpg)
describe Course do describe '#attendee_per_lesson' do let(:student) { Fabricate(:student) } let(:event) { Fabricate(:event) } let(:course) { event.courses.first }
subject { course }
before do student.subscribe(course) Student.create(name: 'Bob').subscribe(course) end
its('attendee_count.first') do should == [course.lessons[0], 2] end
![Page 52: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/52.jpg)
describe Course do describe '#attendee_per_lesson' do let(:student) { Fabricate(:student) } let(:event) { Fabricate(:event) } let(:course) { event.courses.first }
subject { course }
before do student.subscribe(course) Student.create(name: 'Bob').subscribe(course) end
its('attendee_count.first') do should == [course.lessons[0], 2] end
![Page 53: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/53.jpg)
describe Student do # fixture :all let(:student) { Fabricate(:student) }
describe "#register!" do let(:event) { Fabricate(:event) } let(:course) { event.courses.first } let(:another_course) { event.courses.last }
subject { student }
before do student.subscribe(course) student.register!(another_course.lessons[3]) end
its(:registering_lessons) do should include(another_course.lessons[3]) end
![Page 54: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/54.jpg)
Solu
tion
Share your testing context.
![Page 56: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/56.jpg)
✓naming each✓naming them
![Page 57: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/57.jpg)
✓naming each✓naming them
![Page 58: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/58.jpg)
“Generates a method whose return value is memoized after the first call.
describe 'TheAnswer' do let(:answer) { 42 } specify { answer.should == 42 }end
![Page 59: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/59.jpg)
✓ name each focusing object.
✓ Build strategy doesn’t matter.
![Page 60: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/60.jpg)
✓naming each✓naming them
![Page 61: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/61.jpg)
✓ RSpec’s shared_context()
✓let()
✓before()
![Page 62: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/62.jpg)
shared_context "A student subscribes a course" do let(:student) { Fabricate(:student) } let(:event) { Fabricate(:event) } let(:course) { event.courses.first }
before do student.subscribe(course) endend
![Page 63: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/63.jpg)
event
course-1
course-2
Alice<student>
registrationsregistrationsregistrationsregistrations
room-1 period-1room-1room-1room-1room-1period-1period-1period-1period-1
lesson-1-1lesson-1-1lesson-1-1lesson-1-1lesson-1-1
lesson-2-1lesson-2-1lesson-2-1lesson-2-1lesson-2-1
A student subscribes a course
![Page 64: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/64.jpg)
require 'spec_helper'require 'student_subscribe_a_course'
describe Student do include_context "A student subscribes a course"
describe "#register!" do let(:another_course) { event.courses.last } subject { student }
before do student.register!(another_course.lessons[3]) end
its(:registering_lessons) do should include(another_course.lessons[3]) end endend
![Page 65: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/65.jpg)
require 'spec_helper'require 'student_subscribe_a_course'
describe Course do include_context "A student subscribes a course"
describe '#attendee_per_lesson' do
subject { course }
before do Student.create(name: 'Bob').subscribe(course) end
its('attendee_count.first') do should == [course.lessons[0], 2] end endend
![Page 66: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/66.jpg)
Express your intention clearly and reduce tiredness to add new test.
✓ naming each w/ let()✓ naming them w/
shared_context()
![Page 67: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/67.jpg)
Solu
tion
Share your testing context.
![Page 68: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/68.jpg)
Conclusion
![Page 69: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/69.jpg)
✓What test should I write first?
✓ Write model unit test.✓I began model test,but it’s difficult to setup data!!
✓ Use multi strategies for multi types of data.
✓It seems good but less DRY. Is there any idea?
✓ Share your testing context.
I’ve talked about.
![Page 70: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/70.jpg)
✓ fixture✓ fixture replacement✓ before/setup block
Use them all which suitable for the data.
![Page 71: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/71.jpg)
Express your intention clearly and reduce tiredness to add new test.
✓ naming each w/ let()✓ naming them w/
shared_context()
![Page 72: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/72.jpg)
May a testbe with you.
![Page 73: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/73.jpg)
![Page 75: Test Context Arrangement Recipebook](https://reader033.vdocuments.net/reader033/viewer/2022051210/54bd17c34a795932448b461b/html5/thumbnails/75.jpg)
May a testbe with you.