Reflekt
Reflective testing.
Traditional testing is fine but it's not perfect. Tests often check for a golden path that works, when errors actually happen when the code or user does something unexpected. And with automated testing humans still have to write the tests.
Reflekt writes the tests for you, and tests in the negative for situations that you wouldn't have noticed. It works out of the box with no extra coding required. Because Reflekt tests your objects as they are used in the normal flow of the application, you get real world test results.
Usage
Add prepend Reflekt
inside a class:
require 'reflekt'
class Example
prepend Reflekt
Use the application as usual and test results will start showing up in the reflections
folder:
Or enable Lit (included with Reflekt) to see reflections via the command line:
Installation
In Gemfile add:
gem "reflekt"
In terminal run:
bundle install
Or:
gem install reflekt
Configuration
Reflekt.configure do |config|
# Reflekt is enabled by default and should be disabled on production.
config.enabled = true
# The amount of reflections to create per method call.
config.reflect_amount = 5
end
See Config.rb
for more configuration options.
Skipping actions
You can configure Reflekt to skip "no undo" methods like deletion and sending email:
class Example
reflekt_skip :method_name
Use reflekt_skip
on the method that saves to the database to avoid persisting test data. If you still want to save test data to the database then use dependency injection to connect to a dummy database.
Skipping render
Use reflekt_skip
on methods that do the final render to the UI to avoid a visual mess of duplicated elements.
β Don't do:
def show(product)
# Business logic.
product.title = "Showing #{product.name}"
# Rendering logic.
puts product
end
β Do:
reflekt_skip :render
# Business logic.
def show(product)
product.title = "Showing #{product.name}"
render(product)
end
# Rendering logic.
def render(product)
puts product
end
How it works
When a method is called in the usual flow of an application, Reflekt runs multiple simulations with different values on that method to see if it can break things, before handing back control to the method to perform its usual task.
Control-Experiment loop
Reflekt builds itself as you build your application.
Terminology:
Control
- A shapshot of real data (a subclass ofReflection
)Experiment
- A shapshot of random data (a subclass ofReflection
)
The loop:
- You write code and run it
- A
Control
reflection is created per method call, tracking input and output - A set of rules are created from each
Control
on how the program works - Many
Experiment
reflections are created per method call, containing random input and output - Each
Experiment
is tested to pass or fail the set of rules previously defined by eachControl
- Results are saved to the
/reflections
directory - Your application returns its usual output
This feedback loop creates better results the more you develop and use your application.
Comparison
Conceptual differences between testing methodologies:
Traditional testing | Generative testing | Reflective testing | |
---|---|---|---|
Automation | β Defined manually | β Defined semi-automatically | β Defined automatically |
Granularity | β Tests PASS or FAIL | β Tests PASS or FAIL | β Tests PASS or FAIL |
Replication | β Tests run externally | β Tests run externally | β Tests run internally |
Feedback | β Tests run periodically | β Tests run periodically | β Tests run in real time |
Tests run internally
Tests run alongside the normal execution of the program using the exact same code. There is no duplicate code in different files/environments calling the same APIs.
Tests run in real time
Multiple simulations run as you develop and use your application.
Consider this logic:
- Tests often check that things work (in the positive)
- Errors happen when things break (in the negative)
- Tests should check more often for the negative
- This can be automated
Philosophy
To keep coding fun. There are too many layers these days. It doesn't just make coding less fun, it makes it harder for new programmers to learn programming.
To stop duplicate code. RIP DRY. You use to hear βDonβt Repeat Yourselfβ a lot but not anymore. Traditional tests are just duplicate code, we don't need them.
To test code better. By completly automating testing we get 100% coverage and test for situations we never thought possible.