test on my ﬁrst job, 13 years ago The only reason I moved into Rails was good testing One of my career goals has been to be super good at automated testing I’ve read most of the books, watched most of the talks and read most of the blogs I’ve written a s*!tload of tests
has a speciﬁc SUT which conceptual parts (“layers”) of the system are tested by extension, which ones aren’t tested some things outside the SUT are replaced by doubles it’s useful to be thinking about it
canned responses sometimes partial EmailSender.stub send_email: true replaces a collaborator for the test asserts interactions always whole object user = double name: 'John' expect(user).to receive(:update). with(name: 'Джон') * this is the Martin Fowler/xUnit Test Patterns terminology. it’s in no way universal (even in RSpec)
examples: model specs, some service specs, classic controller specs integration tests include a few components examples: Rails’ system, functional & integration tests, some service specs end-to-end involve the browser (simulated or real) examples: functional specs, system tests, anything with capybara This is not how I organise the spec/ directory. It’s just how I think about tests in general.
way (they make you distrust your test failures) Brittle tests are ones that fail due to unrelated changes in functionality (they make changes/refactoring unnecessarily harder) Both should be avoided carefully
invalid • Email already taken • Spaces around email should be trimmed • First name is blank • Last name is blank • Phone number is empty • Phone number is invalid • … 2 end-to-end tests happy path unhappy path 9+ unit tests (assuming there is a Registration object)
long running suites can mock and stub aggressively cares about regression, but will be pragmatic after a point tests should help do changes faster, not slower QA runs tests when the work is done wouldn’t mind waiting longer periods (saves manual work) can’t tweak system internals cares only about correctness and regression extra time is well spent if it catches regressions
interface they depend on Whey you mock/test in isolation, the tests depend on the interface between the objects Refactorings that change the interface get harder You should avoid mocking things that don’t
before do log_in_as :not_bookkeeper ChangeAccountant::RequestInvitation.stub new: request_invitation end describe 'GET new' do it 'renders the new template' do get :new response.should render_template :new end end describe 'POST create' do it 'responds with reset_content on success' do request_invitation.stub execute: true get :create response.should have_http_status :reset_content end it 'renders new template on failure' do request_invitation.stub execute: false get :new response.should render_template :new end end end “Good” example
not “Development” Debatable whether it’s the optimal way to design However, test’s do provide some feedback on the design – simpler mocks and simpler tests usually mean nicer abstractions They also provide some design pressure on the next person who changes the code
values As a Dev, don’t abdicate testing only because you have a QA team Tests have a cost, be careful how you spend it Brittle and erratic tests only increase that cost Be careful with mocks – they are useful, but only when done right (stubs are ﬁne)
context RSpec? Doesn’t really matter, not a big deal Cucumber Is this still a thing? I suggest you don’t go there 100% Test Coverage It’s cheaply achievable in new things if you’re very good in TDD Anything else? Well, ask a question!