Slide 1

Slide 1 text

3BJMT5FTUJOH8PSLTIPQ 'PS#FHJOOFST

Slide 2

Slide 2 text

%PXOMPBE-BUFTU$PEF If you downloaded last night If you never downloaded $ git pull -f $ git clone https://github.com/chitsaou/test-workshop.git Then run $ bundle install --local This workshop is for beginners. If you know how to test Rails apps, this workshop is not for you.

Slide 3

Slide 3 text

:V$IFOH$IVBOH ˖ 3BJMTEFWFMPQFSXJUIZFYQFSJFODFT ˖ 8PSLJOHBU4QPPO3PDLFU*OD ˖ 5XJUUFS!ZPSLYJO

Slide 4

Slide 4 text

"QPMPHJ[F ˖ *EJEOUQSFQBSFUIJTXPSLTIPQWFSZXFMM ˖ :PVSXPSLTXJMMMPTFBOEXJMMCFPWFSSJEEFOCZNZBOTXFSTEVSJOH UIFXPSLTIPQ ˖ :PVSFHPJOHUPMFBSOWFSZCBTJDUFDIOJRVFTPG34QFDPOMZ ˖ 4PSSZGPSUIBU BOEXFMDPNFGPSBOZGFFECBDL

Slide 5

Slide 5 text

"HFOEB ˖ 8IZXFOFFEUFTUJOH ˖ 4FUUJOHVQ34QFD ˖ #BTJD5FTUJOH4ZOUBY ˖ 3FRVFTU5FTUJOH $POUSPMMFS 
 ˖ 'BDUPSZ ˖ "DUJPO.BJMFS5FTUJOH ˖ 4IBSFE$POUFYU&YBNQMFT ˖ &OEJOH3FGFSFODFT

Slide 6

Slide 6 text

'PS&WFSZPOFT(PPE ˖ .BOVBMMZ2"JTUJSJOH.BDIJOFEPSFQFBUJOHKPCTCFUUFS ˖ &OTVSFUIBUDPEFDIBOHFTEPFTOPUCSFBLPUIFSUIJOHT ˖ *GUFTUGBJMT EPOUNFSHFBOEEPOUSFMFBTF ˖ 4BWFZPVSTFMG TBWFZPVSDPMMFBHVFT BOETBWFUIFXPSME

Slide 7

Slide 7 text

34QFD

Slide 8

Slide 8 text

34QFD ˖ "UFTUJOHGSBNFXPSL ˖ 5IFNPTUVTFEPOFJO3VCZXPSME OPUPOMZGPS3BJMT  ˖ 5POTPGQPXFSGVMQMVHJOTJODMVEJOHCSPXTFSCBTFEUFTUJOH DBQZCBSB  ˖ &BTZUPVOEFSTUBOE4ZOUBY

Slide 9

Slide 9 text

4FUVQ34QFD (I've done this for you, so you don't have to do this) # Gemfile group :development, :test do gem 'rspec-rails', '~> 3.1.0' end ! # Run $ bundle install $ rails generate rspec:install

Slide 10

Slide 10 text

spec ├── controllers ├── fixtures ├── helpers ├── mailers ├── models ├── requests ├── routing ├── views ├── spec_helper.rb └── rails_helper.rb ✔ ✔ ✔ ✔

Slide 11

Slide 11 text

3VO5FTU$BTFT # all files $ rspec spec/ ! # specify dir $ rspec spec/models/ ! # single file $ rspec spec/models/post.rb:30 Can specify line number

Slide 12

Slide 12 text

#BTJD34QFD4ZOUBY

Slide 13

Slide 13 text

$ git checkout -f rev-01

Slide 14

Slide 14 text

BQQNPEFMTQPTUSC class Post < ActiveRecord::Base before_create :generate_slug ! private def generate_slug self.slug = self.title.gsub(/[^A-Za-z0-9]+/, '-').downcase end end

Slide 15

Slide 15 text

TQFDNPEFMTQPTU@TQFDSC require 'rails_helper' ! RSpec.describe Post, :type => :model do describe "#slug" do let(:post) { Post.create(:title => "The answer to everything & the university = 42") } ! subject { post.slug } ! it "generates proper slug" do expect(subject).to eq("the-answer-to-everything-the-university-42") end end end

Slide 16

Slide 16 text

EFTDSJCF ˖ "IVNBOSFBEBCMFEFTDSJQUJPOPGBTFUPGUFTUDBTFT ˖ describe "Post" describe "auto reloading" ˖ $BOCFBOZTUSJOH ˖ 6TVBMMZBNFUIPEOBNFJTTUBSUFEXJUI# FH#publish

Slide 17

Slide 17 text

MFU ˖ EFDMBSFTTVQQMFNFOUBMPCKFDUTJOUIJTTDPQF JOdescribeFUD  ˖ let(:post) { Post.create(…) } ˖ -B[ZFWBMVBUFEXJMMOPUCFSVOVOUJMSTUFYFDVUJPO ˖ UPGPSDFFWBMVBUFVQPOEFDMBSBUJPO VTFlet! MFUCBOH

Slide 18

Slide 18 text

TVCKFDU ˖ EFDMBSFTUIFTVCKFDUDIBSBDUFSPGZPVSUFTUDBTFTJOBTDPQF ˖ subject { post.slug } ˖ PGDPVSTFZPVDBOVTFMFUTVCKFDUJTKVTUBTZOUBYTVHBS ˖ UIFSFBSFNPSFTZOUBYTVHBSTXJUIJU FHits OPUDPWFSJOHUPEBZ

Slide 19

Slide 19 text

FYQFDU ˖ 5IFNBUDIFSˋXFDIFDLCFIBWJPSTSFTVMUTXJUIJU ˖ expect(post.slug).to eq "blahblah" ˖ 5IFSFBSFNBOZNBUDIFSTJO34QFD DIFDL
 IUUQTSFMJTIBQQDPNSTQFDSTQFDFYQFDUBUJPOT ˖ :PVDBODSFBUFZPVSPXONBUDIFSTUPP OPUDPWFSJOHUPEBZ

Slide 20

Slide 20 text

&BTZ IVI $ git checkout -f exercise-01 Let's try it

Slide 21

Slide 21 text

BQQNPEFMTQPTUSC class Post < ActiveRecord::Base before_create :set_draft ! private def set_draft self.state = "draft" end end

Slide 22

Slide 22 text

TQFDNPEFMTQPTU@TQFDSC ! describe "default state" do # add let and subject here ! it "is draft" do # add expect here end end 10 minutes exercise

Slide 23

Slide 23 text

TQFDNPEFMTQPTU@TQFDSC ! describe "default state" do let(:post) { Post.create(:title => "Hello! World") } ! subject { post.state } ! it "is draft" do expect(subject).to eq "draft" end end $ git checkout -f answer-01

Slide 24

Slide 24 text

$ git checkout -f rev-02

Slide 25

Slide 25 text

BQQNPEFMTQPTUSC class Post < ActiveRecord::Base def publish! self.update(:state => "published") end end

Slide 26

Slide 26 text

TQFDNPEFMTQPTU@TQFDSC describe "#publish!" do let(:post) { Post.create(:title => "Don't Care") } ! before { post.publish! } ! subject { post.state } ! it "becomes published" do expect(subject).to eq "published" end end

Slide 27

Slide 27 text

CFGPSF ˖ 3VOTDPEFTOJQQFUTCFGPSFFBDIUFTUDBTFJOUIJTTDPQF ˖ before { post.publish! } ˖ (PPEGPSQSFQBSJOHGPSUIFUBSHFUPCKFDU ˖ 5IFSFBSFBMTPafterBOEaround OPUDPWFSJOHUPEBZ

Slide 28

Slide 28 text

DPOUFYU ˖ *G$POEJUJPOGPS34QFD CVUGPSIVNBOSFBEJOHPOMZ ˖ context "when the post is published" do …

Slide 29

Slide 29 text

TUVCCJOH ˖ "TTVNFBOPCKFDUTNFUIPEBMXBZTSFUVSOTBXBOUFEWBMVF • allow(post).to receive(:state) { "draft" } ˖ 6TFGVMGPSPCKFDUTUBUVTBTTVNQUJPO ˖ FHBTTVNFUIBUpost.stateBMXBZTSFUVSOT"draft" ˖ 6TVBMMZSVOTJOBCFGPSFCMPDL

Slide 30

Slide 30 text

$ git checkout -f exercise-02 &YFSDJTF5JNF Finish #can_publish? and #to_param tests in spec/models/post_spec.rb 20 minutes exercise

Slide 31

Slide 31 text

$ git checkout -f answer-02 "OTXFSTUP&YFSDJTF

Slide 32

Slide 32 text

3FRVFTU5FTUJOH GPS$POUSPMMFST

Slide 33

Slide 33 text

8IBUJT3FRVFTU5FTUJOH ˖ )5513FRVFTUUFTUJOH ˖ 1FSGPSNTIJHIMFWFM)551SFRVFTUUFTUJOHBHBJOTUDPOUSPMMFST ˖ $BSFTBCPVU)551SFTQPOTFTJOTUFBEPGWBSJBCMFTJUVTFE ˖ 6TFGVMGPSUFTUJOH"1*T

Slide 34

Slide 34 text

8IZ3FRVFTU5FTUJOH ˖ $POUSPMMFSIBOEMFT)551SFRVFTUT ˖ 5FTUJOHBDPOUSPMMFSMJLFBCMBDLCPYBUIJHIFSMFWFMJTCFUUFS ˖ UIBOUFTUJOHBDPOUSPMMFSTEFUBJMFEWBSJBCMFBTTJHONFOUT

Slide 35

Slide 35 text

$ git checkout -f rev-03

Slide 36

Slide 36 text

BQQDPOUSPMMFSTDPNNFOUT@DPOUSPMMFSSC def create @comment = @post.comments.build(comment_params) ! if @comment.save redirect_to post_url(@post) else flash.alert = "(skip…)" render "posts/show" end end

Slide 37

Slide 37 text

TQFDDPOUSPMMFSTDPNNFOUT@DPOUSPMMFS@TQFDSC RSpec.describe "Comments", :type => :request do describe "POST /posts/xxx/comments" do subject { post "/posts/1/comments", :comment => comment_params } ! let(:comment_params) { {:author => "John Appleseed", :content => "Good article. I like it." } } ! context "a post that is published" do before { the_post.publish! } ! it "creates a new comment" do expect { subject }.to change { the_post.comments.count }.by(1) ennnnd request tests always tagged as request describe is usually written as HTTP request syntax subject is defined as "executing a http request" matching against database changes (will write to DB)

Slide 38

Slide 38 text

$ git checkout -f exercise-03 &YFSDJTF5JNF Finish the cases that does not allow comments 10 minutes exercise spec/requests/comments_spec.rb

Slide 39

Slide 39 text

'BDUPSZ

Slide 40

Slide 40 text

8IBU'BDUPSZ ˖ *LOPX ZPVWFBMSFBEZCFFOUJSFEEPJOHUIJT • let(:post) { Post.create(:title => "blah blah") } ˖ *KVTUEPOUDBSFBCPVUUIFEFUBJMFEBUUSJCVUFT ˖ *UTUJNFGPS'BDUPSZ

Slide 41

Slide 41 text

'BDUPSZ ˖ 0CKFDUTHFOFSBUPS XJUIEFGBVMU SBOEPN EFUBJMFEBUUSJCVUFT ˖ FH:PVEPOUDBSFBVTFSTOBNF BQPTUTUJUMF ˖ FH:PVXBOUUPHFOFSBUFTFRVFOUJBMWBMVFT CPU CPU  ˖ "MTPDBOIPPLNFUIPETEVSJOHHFOFSBUJPO

Slide 42

Slide 42 text

'BCSJDBUJPO HFN ˖ 0OFPGGBDUPSZQMVHJOTGPS3VCZ BOPUIFSPOFJT'BDUPSZ(JSM  ˖ &BTZUPVTFCVUGFXFSGFBUVSFTUIBO'BDUPSZ(JSM

Slide 43

Slide 43 text

'BLFS HFN ˖ 3BOEPNEBUBHFOFSBUPS ˖ (FOFSBUFTTFOUFODFT XPSET IVNBOOBNFT FNBJMT UFMFQIPOF OVNCFST FUD ˖ /PNPSFUIJOLJOHBCPVUFYBNQMFXPSET

Slide 44

Slide 44 text

$ git checkout -f rev-04

Slide 45

Slide 45 text

*OTUBMMBUJPO group :development, :test do gem 'faker' end ! group :test do gem 'fabrication' end (I've done this for you, so you don't have to do this) fabrication is only recommended for test env

Slide 46

Slide 46 text

TQFDGBCSJDBUPSTQPTU@GBCSJDBUPSSC Fabricator(:post) do title { Faker::Lorem.sentence } body { Faker::Lorem.paragraph(3) } end ! Fabricator(:published_post, :from => :post) do after_create { |post| post.publish! } end

Slide 47

Slide 47 text

let(:post) { Post.create(:title => "Don't Care") } let(:post) { Fabricate(:post) }

Slide 48

Slide 48 text

let(:post) { Post.create(:title => "univ. answer is 42") } let(:post) { Fabricate(:post, :title => "univ. answer is 42") }

Slide 49

Slide 49 text

$ git checkout -f exercise-04 &YFSDJTF5JNF Simplify 4 let's in spec/requests/comments_spec.rb 15 minutes exercise

Slide 50

Slide 50 text

$ git checkout -f answer-02 "OTXFSTUP&YFSDJTF

Slide 51

Slide 51 text

"DUJPO.BJMFS5FTUJOH

Slide 52

Slide 52 text

)PXUP5FTU"DUJPO.BJMFS ˖ 8FDBOUTFOEUIFFNBJMUPUIFSFBMXPSMEEVSJOHUFTUJOH ˖ *O3BJMT CZEFGBVMU UFTUFOWEPFTOPUTFOEFNBJM ZBZ  ˖ 5IFSFJTBTQFDJBMNBJMCPYUPDPMMFDUPVUHPJOHNBJMT • ActionMailer::Base.deliveries ˖ 8FDPMMFDUUIFNBJMTGSPNUIFSFBOENBUDIBHBJOTUJU

Slide 53

Slide 53 text

$ git checkout -f 0753cce

Slide 54

Slide 54 text

4FUVQ # spec/macros/mailer_macros.rb module MailerMacros def last_email ActionMailer::Base.deliveries.last end ! def reset_email ActionMailer::Base.deliveries = [] end end (I've done this for you, so you don't have to do this)

Slide 55

Slide 55 text

4FUVQ (I've done this for you, so you don't have to do this) ! # spec/spec_helper.rb require "macros/mailer_macros" … config.include(MailerMacros)

Slide 56

Slide 56 text

TQFDNBJMFST BENJO@OPUJDBJUPO@NBJMFS@TQFDSC RSpec.describe AdminNotificaitonMailer, :type => :mailer do describe "new_comment" do let(:comment) { Fabricate(:comment) do post { Fabricate(:post, :title => "Awesome Article") } end } ! before { AdminNotificaitonMailer.new_comment(comment).deliver }

Slide 57

Slide 57 text

TQFDNBJMFST BENJO@OPUJDBJUPO@NBJMFS@TQFDSC let(:mail) { last_email } ! it "renders the headers" do expect(mail.subject).to eq("[Blog] Awesome Article got a new comment.") expect(mail.to).to eq(["[email protected]"]) expect(mail.from).to eq(["[email protected]"]) end ! it "renders the body" do expect(mail.body.encoded).to match("Awesome Article got a new comment.") end end We can use 'subject' but it will be confused with 'subject of mail'.

Slide 58

Slide 58 text

(sorry, no exercise)

Slide 59

Slide 59 text

#VUXIBUJG*XBOUUPTFFJU ˖ 6TFMFUUFS@PQFOFSIUUQTHJUIVCDPNSZBOCMFUUFS@PQFOFS ˖ 8IFOZPVTFOEBOFNBJMJOEFWFMPQNFOUFOW JUPQFOTUIFFNBJM JOZPVSCSPXTFS ˖ #FXBSFPGCBUDIFNBJM:PVSCSPXTFSXJOEPXXJMMCFCMPBUFE

Slide 60

Slide 60 text

4IBSFE$POUFYU&YBNQMFT

Slide 61

Slide 61 text

4IBSFEDPOUFYUFYBNQMFT ˖ 8FDBODPMMFDUTBNFDPOUFYUTFYBNQMFTUPHFUIFS ˖ "OESFVTFUIFNJOEFTDSJCFDPOUFYU

Slide 62

Slide 62 text

$ git checkout -f rev-05

Slide 63

Slide 63 text

4IBSFE$POUFYU ˖ shared_context "when post is published" { … } ˖ 6TFMFUCFGPSFTVCKFDUJOJU KVTUMJLFBOPSNBMDPOUFYU • include_context "when post is published" ˖ JOEFTDSJCFDPOUFYUCMPDLT

Slide 64

Slide 64 text

TQFDNPEFMTQPTU@TQFDSC shared_context "a post whose state is published" do let(:post) { Fabricate(:published_post) } end declare a shared context

Slide 65

Slide 65 text

TQFDNPEFMTQPTU@TQFDSC context "a post whose state is published" do include_context "a post whose state is published" context "a post whose state is published" do let(:post) { Fabricate(:published_post) } include it in another context

Slide 66

Slide 66 text

4IBSFE&YBNQMFT ˖ shared_examples "not creating a new comment" { … } ˖ 6TFJUCMPDLTJOJU:PVDBOIBWFBTNBOZBTZPVXBOU • it_behaves_like "not creating a new comment" ˖ JOEFTDSJCFDPOUFYUCMPDLT ˖ PSJODMVEF@FYBNQMFT

Slide 67

Slide 67 text

TQFDSFRVFTUTDPNNFOUT@TQFDSC shared_examples "not creating a new comment" do it "does not create a new comment" do expect { subject rescue nil # ignore any exception }.not_to change { the_post.comments.count } end end declare a shared example

Slide 68

Slide 68 text

TQFDSFRVFTUTDPNNFOUT@TQFDSC it_behaves_like "not creating a new comment" it "does not create a new comment" do expect { subject rescue nil # ignore any exception }.not_to change { the_post.comments.count } end include it in a context or description

Slide 69

Slide 69 text

(sorry, no exercise)

Slide 70

Slide 70 text

8"3/*/( ˖ *UTLJOEBSFGBDUPSJOHCVUEPOUEPJUUPPNVDI ˖ 5FTUTTIPVMECFTUVQJEBOEFBTZUPSFBE FWFOXEVQMJDBUJPOT ˖ %POUNJYTIBSFEFYBNQMFTBOETIBSFEDPOUFYUTUPHFUIFSˋXJMM CFDPNFIBSEUPSFBEFWFOUVBMMZ ˖ #BETUSVDUVSFETIBSFEHSPVQTNBLFUFTUTIBSEUPSFBE

Slide 71

Slide 71 text

&OEJOH

Slide 72

Slide 72 text

3FGFSFODFT ˖ 34QFD%PDIUUQSTQFDJOGP ˖ &WFSZEBZ3BJMT5FTUJOHXJUI34QFDIUUQTMFBOQVCDPN FWFSZEBZSBJMTSTQFD