{"id":13879002,"url":"https://github.com/refIekt/reflekt","last_synced_at":"2025-07-16T15:30:33.137Z","repository":{"id":42696140,"uuid":"277838805","full_name":"refIekt/reflekt","owner":"refIekt","description":"Reflective testing.","archived":false,"fork":false,"pushed_at":"2023-02-11T15:56:10.000Z","size":1147,"stargazers_count":130,"open_issues_count":8,"forks_count":5,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-08-07T08:12:00.673Z","etag":null,"topics":["fuzzing","generative","reflection","reflective-testing","reflekt","testing"],"latest_commit_sha":null,"homepage":"https://reflekt.dev","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/refIekt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2020-07-07T14:27:02.000Z","updated_at":"2023-04-06T00:12:50.000Z","dependencies_parsed_at":"2023-02-17T01:46:39.045Z","dependency_job_id":null,"html_url":"https://github.com/refIekt/reflekt","commit_stats":null,"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refIekt%2Freflekt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refIekt%2Freflekt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refIekt%2Freflekt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/refIekt%2Freflekt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/refIekt","download_url":"https://codeload.github.com/refIekt/reflekt/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":226138849,"owners_count":17579496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fuzzing","generative","reflection","reflective-testing","reflekt","testing"],"created_at":"2024-08-06T08:02:06.647Z","updated_at":"2024-11-24T07:31:28.004Z","avatar_url":"https://github.com/refIekt.png","language":"Ruby","readme":"# Reflekt\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/Logo.svg\" raw=true width=\"200\" style=\"margin-left: auto; margin-right: auto;\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://www.mozilla.org/MPL/2.0/\" alt=\"MPLv2 License\"\u003e\n    \u003cimg src=\"https://img.shields.io/badge/license-MPLv2-blue.svg\" /\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://rubygems.org/gems/reflekt\"\u003e\n    \u003cimg src=\"https://badge.fury.io/rb/reflekt.svg\" alt=\"Gem Version\" /\u003e\n  \u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/github/languages/code-size/refIekt/reflekt\" alt=\"GitHub code size in bytes\"\u003e\n  \u003cimg src=\"https://img.shields.io/gem/dt/reflekt\"\u003e\n  \u003ca href=\"https://www.codetriage.com/refiekt/reflekt\" alt=\"Open Source Helpers\"\u003e\n    \u003cimg src=\"https://www.codetriage.com/refiekt/reflekt/badges/users.svg\" /\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n*Reflective testing.*\n\nTraditional 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.\n\n**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.\n\n## Usage  \n\nAdd `prepend Reflekt` inside a class:\n```ruby\nrequire 'reflekt'\n\nclass Example\n  prepend Reflekt\n```  \n\nUse the application as usual and test results will start showing up in the `reflections` folder:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/Screenshot.png\" raw=true style=\"margin-left: auto; margin-right: auto;\"/\u003e\n\u003c/p\u003e\n\nOr enable \u003ca href=\"https://github.com/refIekt/lit\"\u003eLit\u003c/a\u003e (included with Reflekt) to see reflections via the command line:\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/Lit.png\" raw=true style=\"margin-left: auto; margin-right: auto;\" width=\"850\"/\u003e\n\u003c/p\u003e\n\n## Installation\n\nIn Gemfile add:\n```ruby\ngem \"reflekt\"\n```  \n\nIn terminal run:\n```\nbundle install\n```\n\nOr:\n```\ngem install reflekt\n```\n\n## Configuration\n\n```ruby\nReflekt.configure do |config|\n  # Reflekt is enabled by default and should be disabled on production.\n  config.enabled = true\n\n  # The amount of reflections to create per method call.\n  config.reflect_amount = 5\nend\n```\n\nSee `Config.rb` for more configuration options.\n\n## Skipping actions\n\nYou can configure Reflekt to skip \"no undo\" methods like deletion and sending email:\n\n```ruby\nclass Example\n  reflekt_skip :method_name\n```\n\nUse `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](https://www.reddit.com/r/programming/comments/iz3rks/if_youre_not_practicing_within_the_scope_of_a/g6i1ex3/) to connect to a dummy database.\n\n## Skipping render\n\nUse `reflekt_skip` on methods that do the final render to the UI to avoid a visual mess of duplicated elements.\n\n**❌ Don't do:**\n```ruby\ndef show(product)\n  # Business logic.\n  product.title = \"Showing #{product.name}\"\n\n  # Rendering logic.\n  puts product\nend\n```\n\n**✅ Do:**\n```ruby\nreflekt_skip :render\n\n# Business logic.\ndef show(product)\n  product.title = \"Showing #{product.name}\"  \n  render(product)\nend\n\n# Rendering logic.\ndef render(product)\n  puts product\nend\n```\n\n## How it works\n\nWhen 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.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"./assets/Flowchart.svg\" raw=true width=\"600\" style=\"margin-left: auto; margin-right: auto;\"/\u003e\n\u003c/p\u003e\n\n\n### Control-Experiment loop\n\nReflekt builds itself as you build your application.\n\n**Terminology:**\n* `Control` - A shapshot of real data (a subclass of `Reflection`)\n* `Experiment` - A shapshot of random data (a subclass of `Reflection`)\n\n**The loop:**\n1. You write code and run it\n2. A `Control` reflection is created per method call, tracking input and output\n3. A set of rules are created from each `Control` on how the program works\n4. Many `Experiment` reflections are created per method call, containing random input and output\n5. Each `Experiment` is tested to pass or fail the set of rules previously defined by each `Control`\n6. Results are saved to the `/reflections` directory\n7. Your application returns its usual output\n\nThis feedback loop creates better results the more you develop and use your application.\n\n## Comparison\n\nConceptual differences between testing methodologies:\n\n|                   | Traditional testing       | Generative testing           | Reflective testing        |\n--------------------|---------------------------|------------------------------|---------------------------|\n| **Automation**    | ❌ Defined manually       | ❎ Defined semi-automatically | ✅ Defined automatically  |\n| **Granularity**   | ✅ Tests PASS or FAIL     | ✅ Tests PASS or FAIL         | ✅ Tests PASS or FAIL     |\n| **Replication**   | ❌ Tests run externally   | ❌ Tests run externally       | ✅ Tests run internally   |\n| **Feedback**      | ❌ Tests run periodically | ❌ Tests run periodically     | ✅ Tests run in real time |\n\n**Tests run internally**  \nTests 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.\n\n**Tests run in real time**  \nMultiple simulations run as you develop and use your application.\n\n**Consider this logic:**  \n1. Tests often check that things work (in the positive)  \n2. Errors happen when things break (in the negative)  \n3. Tests should check more often for the negative  \n4. This can be automated\n\n## Philosophy\n\n**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.\n\n**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.\n\n**To test code better.** By completly automating testing we get 100% coverage and test for situations we never thought possible.\n","funding_links":[],"categories":["Ruby"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FrefIekt%2Freflekt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FrefIekt%2Freflekt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FrefIekt%2Freflekt/lists"}