{"id":26658168,"url":"https://github.com/ltbringer/fastest","last_synced_at":"2025-04-11T13:07:55.983Z","repository":{"id":57428578,"uuid":"165459577","full_name":"ltbringer/fastest","owner":"ltbringer","description":"Watches python code and creates test cases","archived":false,"fork":false,"pushed_at":"2019-03-29T06:37:14.000Z","size":1094,"stargazers_count":10,"open_issues_count":4,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-25T09:18:47.703Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Jupyter Notebook","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ltbringer.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-01-13T02:58:21.000Z","updated_at":"2023-03-05T02:08:15.000Z","dependencies_parsed_at":"2022-09-02T15:31:46.876Z","dependency_job_id":null,"html_url":"https://github.com/ltbringer/fastest","commit_stats":null,"previous_names":["amreshvenugopal/fastest"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ltbringer%2Ffastest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ltbringer%2Ffastest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ltbringer%2Ffastest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ltbringer%2Ffastest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ltbringer","download_url":"https://codeload.github.com/ltbringer/fastest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248404516,"owners_count":21097765,"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":[],"created_at":"2025-03-25T09:18:52.228Z","updated_at":"2025-04-11T13:07:55.962Z","avatar_url":"https://github.com/ltbringer.png","language":"Jupyter Notebook","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Fastest\nCreates unit tests from examples in the docstring and more.\n\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/ae01d1185a9b4e93be06e6faf894448d)](https://app.codacy.com/app/AmreshVenugopal/fastest?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=AmreshVenugopal/fastest\u0026utm_campaign=Badge_Grade_Dashboard)\n[![Scrutinizer_Badge](https://scrutinizer-ci.com/g/AmreshVenugopal/fastest/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/AmreshVenugopal/fastest/)\n[![Coverage Status](https://coveralls.io/repos/github/AmreshVenugopal/fastest/badge.svg?branch=master)](https://coveralls.io/github/AmreshVenugopal/fastest?branch=master)\n[![Build_Status](https://travis-ci.org/AmreshVenugopal/fastest.svg?branch=master)](https://travis-ci.org/AmreshVenugopal/fastest)\n[![Current_Version](https://img.shields.io/pypi/v/fastest.svg)](https://pypi.org/project/fastest/)\n[![Python_Version](https://img.shields.io/pypi/pyversions/fastest.svg)](https://pypi.org/project/fastest/)\n\n## Install\n\n```bash\n$ pip install fastest\n```\n\n## Usage\n```bash\n$ fastest\n```\nwatches all .py files and creates coverage for entire project.\n\n```bash\n$ fastest --path=$(pwd) --source=py_module\n```\nwhere `path` is the the project root, and [`source`](https://coverage.readthedocs.io/en/coverage-4.3.4/source.html#source) \nis same as the value passed to the command `coverage run -m unittest --source=$source test`\n\n```bash\n$ fastest --exclude=dont_check_this_dir/*,these__*.py\n```\n\nTo exclude files/folders use `--exclude` and the file watcher will ignore them.\nThe `test/*` folder that `faster` creates is excluded by default.\n\n\n```bash\n$ fastest --poll-duration=10\n```\nBuilds files, runs tests and coverage every `10s`, default = `1s`\n\nThings that happen when you run `python main.py --path=$(pwd)`:\n\n 1. Checks for a `test` file at the project root, it creates if it doesn't find one.\n 2. Watches `.py` files for changes.\n 3. Creates unittests if a function has examples in its docstrings like so:\n\n```python\n# .\n# ├──module_a\n# ├──module_b\n#    └── utils.py\n#\ndef add(x, y):\n    \"\"\"\n    ----\n    examples:\n    1) add(3, 4) -\u003e 7\n    \"\"\"\n    return x + y\n```\n\n This will create a unittest in the `test` directory, `assertEqual(add(3, 4), 7)`\n within `Class test_\u003cfile\u003e_\u003cfunction\u003e(self)` \n (for the given directory, tree: `Class test_utils_add(self)`)\n\n 4. Runs all tests that are created.\n 5. Creates a coverage report (in html format).\n 6. Print the link to the coverage reports' index.html.\n\n## How to make best use of Fastest\n 1. Keep your `functions` light:\n    - Be paranoid about separation of concerns.\n    - Too many conditions are a hint that you might need another function.\n    - Complex loops and `if-else` are not scalable code, a single mistake would \n    take that tower down and feature additions would involve someone going through \n    that brain-teaser.\n 2. Use libraries but wrap them with your own functions. Like: Use `requests` or the inevitable database? \n    wrap them with your own functions.\n    - Helps with adding customizations in one place (configuring things like base url, and similar configs)\n    - Helps mocking so that entire code-base can be unit tested.\n 3. Docstrings may get outdated if your work pace is too fast to maintain quality documentation. \n    Now adding examples now would help you create \n    tests which prevents your descriptions from going stale, **if the tests fail, \n    probably the documentation needs a second look too**. This is enforced within Fastest, as documentation **IS**\n    contributing to tests.\n\n\n## Examples:\n 1. Allows creation of variables within the docstrings, which includes lambda functions!\n     ```python\n    def quick_maths(a, b):\n        \"\"\"\n        ----\n        examples:\n        @let \n        a = {\n            'apples': 3,\n            'oranges': 4\n        }\n        @end\n        \n        1) quick_maths(a['apples'], a['oranges']) -\u003e 7\n        ----\n        \"\"\"\n        return a + b\n     ```\n 2. You can run any valid python code within `@let--@end` blocks.\n 3. Can include installed modules external to your project.\n     ```python\n    def current_time():\n        \"\"\"\n        ---\n        examples:\n        @need\n        from datetime import datetime\n        @end\n        1) current_time() -\u003e datetime.now()\n        \"\"\"\n        return datetime.now()\n     ```\n 4. If types are added to docstring, Fastest will create tests\n for checking type of the value returned against empty of arguments.\n    ```python\n    def chain_strings(str1, str2):\n        \"\"\"\n        :param str1: str\n        :param str2: str\n        :return: str\n        \"\"\"\n        return str1 + str2\n    ``` \n    Fastest will create a `assertInstanceIs(chain_strings('', ''), str)` for the above snippet.\n 5. To create an `assertRaises` test-case:\n     ```python\n    def crashes_sometimes(input_string):\n        \"\"\"\n        ----\n        examples: \n    \n        !! crashes_sometimes(None) -\u003e ValueError\n        ----\n        \"\"\"\n        if not input_string:\n            raise ValueError\n        return input_string\n     ```\n    The syntax marked with `!! crashes_sometimes(None) -\u003e ValueError` handles exceptions\n    that the code throws\n\n## Fuzzing json apis \n*Note: work in progress*\n\nAn experimental feature that can test your api's (currently supporting json request bodies only!). \nA happy-case example is required and fastest will figure out the rest, it will e-mail the errors to you.\n\n\n*example-case:*\n```js \nrouter.post('/test', function(req, res, next) {\n  const { messageObject } = req.body;\n  res.json({ prop: messageObject.message });\n});\n```\nThe above is a snippet from an express-server's post request. It expects a `messageObject` within the `req.body`.\nThis api returns a response containing `messageObject.message` without ever checking if it is present.\n\nHate mistakes like these?\nMake sure to check out the [fuzz.log](https://github.com/AmreshVenugopal/fastest/blob/master/fuzz.log).\n\n```text\nurl: /test\nrequest_body: {'messageObject': None}\nresponse: \u003c!DOCTYPE html\u003e\u003chtml\u003e\u003chead\u003e\u003ctitle\u003e\u003c/title\u003e\u003clink rel=\"stylesheet\" href=\"/stylesheets/style.css\"\u003e\u003c/head\u003e\u003cbody\u003e\u003ch1\u003eCannot read property 'message' of null\u003c/h1\u003e\u003ch2\u003e\u003c/h2\u003e\u003cpre\u003eTypeError: Cannot read property 'message' of null\n    at /home/ltbringer/programming/js/sample-json-api/routes/index.js:11:34\n    at Layer.handle [as handle_request] (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/layer.js:95:5)\n    at next (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/route.js:137:13)\n    at Route.dispatch (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/route.js:112:3)\n    at Layer.handle [as handle_request] (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/layer.js:95:5)\n    at /home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/index.js:281:22\n    at Function.process_params (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/index.js:335:12)\n    at next (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/index.js:275:10)\n    at Function.handle (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/index.js:174:3)\n    at router (/home/ltbringer/programming/js/sample-json-api/node_modules/express/lib/router/index.js:47:12)\u003c/pre\u003e\u003c/body\u003e\u003c/html\u003e\nstatus_code: 500\n```\n\nThis feature is still under progress because:\n- Signatures that have resulted in errors need to be avoided.\n- A simple to use format in which server request-bodies and other config should be shared is not yet formalized.\n- Error-Grouping: ability to detect when multiple signatures are leading to similar error or affects same area of code is not present.\n- Optimizing happy-case: signatures that don't cause errors and an appropriate response is returned by the server under test, need not be sent back to the server again.\n\n\n# Goals for Fastest\n- [x] Help maintaining tests, code-coverage and documentation.\n- [ ] Help with performance issues within code.\n- [ ] Provide testability score for code.\n- [x] Test functions for auto-generated inputs where the code would crash.\n\n\nFastest uses itself for creating tests and manages a 100% on the coverage!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fltbringer%2Ffastest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fltbringer%2Ffastest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fltbringer%2Ffastest/lists"}