code • We like to have fun with our work • Code that’s easy to change is the most fun to work on • Tests should make our code easier to change Thursday, 22 August 13
class • Knows the name of a message it intends to send to someone other than self • Knows the arguments a message requires • Knows the order of those arguments Thursday, 22 August 13
We want to minimise dependencies • So we want as few tests as possible • And they should test behaviour rather than implementation Thursday, 22 August 13
• Interaction verification (white box / mocks) • Prefer state as it doesn't couple you to implementation • Mockist style can be great when don't know the end state • You’ll end up using both Thursday, 22 August 13
11 it { should have_many :users } 12 it { should validate_presence_of :owner } 13 it { should validate_presence_of :name } 14 it { should have_scope(:active).where(deleted: false) } 15 end • Don’t tell me anything or drive design • Completely coupled to implementation Thursday, 22 August 13
"is required" do 21 expect(subject.errors.on(:name)).to eql(I18n.t('errors.messages.empty')) 22 end 23 end 24 25 describe Project, ".active" do 26 it "doesn't return deleted projects" do 27 live = FactoryGirl.create(:project) 28 FactoryGirl.create(:project, deleted: false) 29 expect(Project.active).to eq([live]) 30 end 31 end • Don’t test things that other tests should cover • Do test things that are important (imho) Thursday, 22 August 13
critical part of your application • Integration tests for every important feature • Unit tests for classes you create yourself to document public apis Thursday, 22 August 13
4 describe "Billing" do 5 let(:email) { “[email protected]” } 6 7 before do 8 @student = create_student email 9 end 10 11 it "allows the student to add funds" do 12 add_funds(50, @student.email) 13 within "#user_balance" do 14 page.should have_text("€50") 15 end 16 end 17 end 18 Thursday, 22 August 13
whenever everything is wired up correctly • Don’t use them as unit tests (testing for negatives) • Don’t use them as acceptance tests Thursday, 22 August 13
2 let(:tutor) { FactoryGirl.create(:tutor) } 3 let(:student) { FactoryGirl.create(:student) } 4 5 before do 6 activate_authlogic 7 end 8 9 it "redirects when no user" do 10 do_action 11 response.should redirect_to("/user_sessions/new") 12 end 13 14 it "redirects when user is tutor" do 15 UserSession.create(tutor) 16 do_action 17 response.should redirect_to("/") 18 flash[:error].should == "That page is for students only" 19 end 20 21 it "performs action when user is a student" do 22 UserSession.create(student) 23 do_action 24 flash[:error].should be_nil 25 end 26 end Thursday, 22 August 13
the command line 2 3 Scenario: Running add 4 In order to add a key and translation content 5 When I have a valid project on localeapp.com with api key "MYAPIKEY" 6 And an initializer file 7 When I run `localeapp add foo.baz en:"test en content" es:"test es content"` 8 Then the output should contain: 9 """ 10 Localeapp Add 11 12 Sending key: foo.baz 13 Success! 14 """ 15 16 Scenario: Running add with no arguments 17 In order to add a key and translation content 18 When I have a valid project on localeapp.com with api key "MYAPIKEY" 19 And an initializer file 20 When I run `localeapp add` 21 Then the output should contain: 22 """ 23 localeapp add requires a key name and at least one translation 24 """ Thursday, 22 August 13
Move logic out into presenter style class and test that • Integration test should be enough to show everything is wired together Thursday, 22 August 13
logic out into domain logic classes and test those • Integration tests enough to show everything is wired together correctly • Shared tests to check security etc. Thursday, 22 August 13
Ignore Expect to send The Unit Testing Minimalist Incoming Type @sandimetz Apr 2013 Message Ignore Sent to Self Outgoing Origin Saturday, April 27, 13 Thursday, 22 August 13
Capybara, and Poltergeist for integration tests • VCR for testing API integration • Timecop for when time is important • Don’t have a go to for acceptance tests. Trying Mechanize, PhantomJS, bash & curl Thursday, 22 August 13