theory rspec Flashcards
RSpec
RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications.
red-green loop
- Write the smallest possible test case that matches what we need to program.
- Run the test and watch it fail. This gets you into thinking how to write only the code that makes it pass.
- Write some code to make the test pass.
- Run your test suite. Repeat steps 3 and 4 until all tests pass.
- Go back and refactor your new code, making it as simple and clear as possible while keeping the test suite green.
describe block
We are using another describe block to describe the add class method. By convention, class methods are prefixed with a dot (“.add”), and instance methods with a dash (“#add”).
context block
We are using a context block to describe the context under which the add method is expected to return zero. context is technically the same as describe, but is used in different places, to aid reading of the code.
it block
We are using an it block to describe a specific example, which is RSpec’s way to say “test case”. Generally, every example should be descriptive, and together with the context should form an understandable sentence. This one reads as “add class method: given an empty string, it returns zero“.
expect(…).to and the negative variant expect(…).not_to
expect(…).to and the negative variant expect(…).not_to are used to define expected outcomes. The Ruby expression they are given (in our case, StringCalculator.add(“”)) is combined with a matcher to fully define an expectation on a piece of code. The matcher we are using here is eq, a basic equality matcher.
purposes of specs
1) to drive development, and 2) as a verification mechanism.
Specs Directory Structure
Model specs reside in the spec/models directory
Controller specs reside in the spec/controllers directory
Request specs reside in the spec/requests directory. The directory can also be named integration or api.
Feature specs reside in the spec/features directory
View specs reside in the spec/views directory
Helper specs reside in the spec/helpers directory
Mailer specs reside in the spec/mailers directory
Routing specs reside in the spec/routing directory
Job specs reside in the spec/jobs directory
System specs reside in the spec/system directory
Model specs
A model spec is a thin wrapper for an ActiveSupport::TestCase, and includes all
of the behavior and assertions that it provides, in addition to RSpec’s own
behavior and expectations.
Controller specs
It allows you to simulate a single http request in each example, and then
specify expected outcomes such as:
rendered templates
redirects
instance variables assigned in the controller to be shared with the view
cookies sent back with the response
Request spec
Request specs provide a thin wrapper around Rails’ integration tests, and are
designed to drive behavior through the full stack, including routing
(provided by Rails) and without stubbing (that’s up to you).
With request specs, you can:
specify a single request
specify multiple requests across multiple controllers
specify multiple requests across multiple sessions
Feature spec
Feature specs are high-level tests meant to exercise slices of functionality
through an application. They should drive the application only via its external
interface, usually web pages.
View spec
Use them to test the content of view templates
without invoking a specific controller.
Helper spec
Helper specs expose a helper object, which includes the helper module being
specified, the ApplicationHelper module (if there is one) and all of the
helpers built into Rails. It does not include the other helper modules in
your app.
To access the helper methods you’re specifying, simply call them directly
on the helper object.
NOTE: helper methods defined in controllers are not included.
Mailer specs
A mailer spec is a thin wrapper for an ActionMailer::TestCase, and includes all
of the behavior and assertions that it provides, in addition to RSpec’s own
behavior and expectations.
Routing specs
Simple apps with nothing but standard RESTful routes won’t get much value from
routing specs, but they can provide significant value when used to specify
customized routes, like vanity links, slugs, etc.
Job spec
Job specs provide alternative assertions to those available in ActiveJob::TestHelper and help assert behaviour of the jobs themselves and that other entities correctly enqueue them.
With job specs, you can:
specify the job class which was enqueued
specify the arguments passed to the job
specify when the job was enqueued until
specify the queue which the job was enqueued to
System spec
System specs are RSpec’s wrapper around Rails’ own
system tests.
System tests allow you to test user interactions with your application,
running tests in either a real or a headless browser. System tests use
Capybara under the hood.
By default, system tests are run with the Selenium driver, using the
Chrome browser, and a screen size of 1400x1400. The next section explains
how to change the default settings.
What is Better Specs
Describe Your Methods
Use contexts
Keep your description short
Single expectation test
Test all possible cases
Expect vs Should syntax
Use subject
Use let and let!
Mock or not to mock
Create only the data you need
Use factories and not fixtures
Easy to read matchers
Shared Examples
Test what you see
Don’t use should
Automatic tests with guard
Faster tests (preloading Rails)
Stubbing HTTP requests
Useful formatter
Describe Your Methods
Be clear about what method you are describing. For instance, use the Ruby documentation convention of . (or ::) when referring to a class method’s name and # when referring to an instance method’s name.
Use contexts
Contexts are a powerful method to make your tests clear and well organized (they keep tests easy to read). When describing a context, start its description with ‘when’, ‘with’ or ‘without’.
Keep your description short
A spec description should never be longer than 40 characters. If this happens you should split it using a context.
Single expectation test
The ‘one expectation’ tip is more broadly expressed as ‘each test should make only one assertion’. This helps you on finding possible errors, going directly to the failing test, and to make your code readable. In isolated unit specs, you want each example to specify one (and only one) behavior. Multiple expectations in the same example are a signal that you may be specifying multiple behaviors.
Anyway, in tests that are not isolated (e.g. ones that integrate with a DB, an external webservice, or end-to-end-tests), you take a massive performance hit to do the same setup over and over again, just to set a different expectation in each test. In these sorts of slower tests, I think it’s fine to specify more than one isolated behavior.
Test all possible cases
Testing is a good practice, but if you do not test the edge cases, it will not be useful. Test valid, edge and invalid case. For example, consider the following action.
The error I usually see lies in testing only whether the resource has been removed. But there are at least two edge cases: when the resource is not found and when it’s not owned. As a rule of thumb think of all the possible inputs and test them.