Improving Ruby on Rails Slow Test Suites
Respecting SOLID goes a long way to making classes testable.
In particular, a layered/hexagonal/service design will abstract persistence, which is the key contributor to slow tests.
Persistence and Business Logic
Use service objects, and avoid persistence in service objects. Service objects usually have a very compact concern and a single public method called `call`.
If your service depends on stored data, avoid loading it in the service object; prefer to delegate that role to query objects (which can be mocked).
A common pattern is to inject repositories:
In consumers of service objects, mock them out, and stub save! in any output objects.
Avoid Business Logic In ActiveRecord Models
Keep “models” thin and never implement business logic in ActiveRecord models.
A different angle on the previous recipe: if your ActiveRecord models are thin, you can mock them out in any service object or other consumer.
Any addition of a method to models, even “sugar” methods (that test or combine attributes), is a smell.
Callbacks are the most robust smell of bad coupling.
If you need to react to persistence events, `after_save` nor observers are your friends. Use a local event bus like the excellent wisper gem.
Wrap and Delegate Behavior
If you need an extension of the ActiveRecord model, write a presenter using SimpleDelegator.