Multi-layer Outside-in BDD
Behaviour Driven Design
for modern Rails apps
A note on these slides
- simplified version of slides from actual workshop
- use MDX-deck
raw MDX deck can be viewed in git repo
- to see speaker notes OPTION-p (
⌥ p
) on mac
Install - code
- git clone git@github.com/failure-driven/bdd-workshop-app.git
- Ruby 2.6.2, Node 10.15.3, PostgreSQL, Chrome
bundle install && yarn install
bin/rails db:create db:migrate
make
bin/rails server
Test Driven Design
- Design a loosely-coupled solution
- Test code implementation of an isolated unit
Behaviour Driven Design
- Deliver stakeholder value
- Test behaviour across many units
Modules
- The Unit Under Test
- When Then Steps
- Flows vs Mechanics
- Add a Feature with Outside-In BDD
Module 1
The Unit Under Test
Testing boundaries
Integration tests and the rest
How does the app work?
Open spec/features/monster_spec.rb
How does the app really work?
Let’s take a look
1. The Unit under Test - Review
Units under test
- Frontend & backend together - Integration
- Backend (API to DB) - Integration
- Components - Isolated unit
- Read tests, understand how the system works
From
Given/When/Then
To
series of When/Then
"When" "Then"
flows through the system
Let's take a look
code dive
2. When Then steps - Review
Integration specs
- ‘When Then’ pair denotes behaviour
- Multiple ‘When Then’ behaviours per scenario
- Owned by developers
- First code you write!
gem rspec-example_steps
Module 3
Flows vs Mechanics
The problem
- Hard to find existing tests
A solution
- Separate different responsibilities
Flows
- Driven by external interface
- Particular sequence of events
- Effects of a series of interactions
- Multiple actors
Mechanics
- Driven by partial interface
- Immediate behaviour of one unit
- Single actor
- No critical flow on effects
- Exercise in more detail
A solution
- Separate different responsibilities
- Organise tests
- Scale your test suite!
Flows
“Making a puppet walk”
Mechanics
“Manipulating a single leg”
Let's take a look
code dive
3. Flows vs Mechanics - Review
- Organise integration tests
- Document how system works
Flows
- Effects of a series of interactions
- Multiple actors
Mechanics
- Immediate behaviour of one unit
- Single actor
Module 4
Add a Feature with Outside-In BDD
Testing boundaries
- Every test is a unit test
Testing boundaries
Flow
- Full system integration
- API, controller, model, db and frontend
- Test flows with core alternate outcomes
Testing boundaries
Mechanic
- Full system integration
- API, controller, model, db and single component
- Test user experience when errors/loading occur
Testing boundaries
Component
- Isolated unit
- Test wrong/missing params passed in
Testing boundaries
API
- Backend integration
- Test valid/invalid request params
- Test response to valid/invalid params
Testing boundaries
Controller
- Isolated unit
- Test collaboration with other units
Testing boundaries
Model (domain)
- Isolated unit
- Test data retrieval
- Test actions performed on that data
New feature
- What is the new feature?
- How do we drive this feature with BDD?
Let's take a look
code dive
Complete the feature
- Flow - pending
- Mechanic - assert age shows up in profile page
- Component - render age in profile component
- API - show view responds with age value
- Controller - show view responds with age value
Model - TDD age method
- return nil when player does not have dob
- calculate age when birthday is today
- calculate age when birthday is tomorrow
- Hint: Timecop.freeze in gemfile
Complete the feature
git pull --rebase OR
git clone git@github.com/failure-driven/bdd-workshop-app.git
- docs/complete_the_feature_challenge.md
- complete solution by [date]
- tweet us if you get stuck @selenasmall88 @saramic
RailsConf 2019
Abigail Phoenix & Marty Haught
Melbourne Ruby & Dev community
Paal Ringstad from @LeWagonMEL
Jessie Wang from Code Mentoring Melbourne
@ceels @NessNimmo @Quintrino
Fresho
Huw Birrell & James Andronis
Fresho Dev Team
Dave, Patrick, Mark, Dan
Perryn Fowler
@perrynfowler