Notes from Effective Testing with RSpec 3, chapter 7.
In Chapter 7 we go in-depth on the different ways of organizing code and making specs readable.
“…readable specs are crucial for communicating your ideas and for long-term maintainability. They show the intent behind the code.”
Excerpt From: Myron Marston, Ian Dees. “Effective Testing with RSpec 3”
# Use a class. RSpec.describe Class do # Use an object. RSpec.describe object do # Provide more context in a string. RSpec.describe object, 'an interface' do # Add a tag for configuring in Hooks and filtering. RSpec.describe Class, 'an adapter library', issue: ABC-123 do RSpec.describe 'a class' do # `context` is an alias for `describe`. context 'in this environment' do it 'does one thing' it 'does another' end describe 'data structure' do # `example` is an alias for `it`. example 'in ordered form' example 'in unordered form' end describe 'api config' do # `specify` is an alias for `it`. specify 'initializer fails when api is not defined' specify 'APIClient.gem specifies dependencies' end end
This section is mostly review of what we already know.
- let method, which uses memoization.
- hooks, run code for setup & teardown. Hooks can happen on examples, groups, the entire suite, or configured for tags.
- Helper methods, regular ruby method, to reduce complexity.
- Modules, regular ruby module, to reduce complexity.
- Sharing Context and Examples to share code in the test context.
We have to be careful when sharing code in our test suites. Remember that it’s not production code. If I sacrifice readability and maintainability for optimization it is a step backward not forward.
Specs should be modular. When it fails we should have everything we need to understand the failure in front of us to resolve the issue.
I was a little ambitious in my refactoring. After comparing my first refactoring to the books example I realized I had missed the point. The goal of our test suit is to be easy to read in the code and execution.
This is the rspec output of my first attempt. I extracted ‘behaves like Parser’ to share between the specs.
Addressable::URI parses the scheme parses the path behaves like Parser identifies schemes host port URI behaves like Parser identifies schemes host port port defaults http to 80 defaults https to 443
It doesn’t read very well as each line is missing context. We cannot randomly pick up a line and understand what we are testing. We have to scan up to know what is happening. The next refactoring has better readability.
Addressable::URI parses the scheme parses the path behaves like a URI Parser identifies the host identifies the port URI behaves like a URI Parser identifies the host identifies the port port defaults http to 80 defaults https to 443
I’ve uploaded my refactoring to GitHub.