{"id":30588733,"url":"https://github.com/schettino72/rut","last_synced_at":"2025-10-08T14:37:50.175Z","repository":{"id":303236842,"uuid":"486699356","full_name":"schettino72/rut","owner":"schettino72","description":"rut - Run Unit Tests","archived":false,"fork":false,"pushed_at":"2025-08-10T11:44:55.000Z","size":205,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-08-28T19:02:57.202Z","etag":null,"topics":["cli","test-runner","testing","testing-framework","testing-tools","unittest"],"latest_commit_sha":null,"homepage":"","language":"Python","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/schettino72.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":"AUTHORS","dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-04-28T18:05:02.000Z","updated_at":"2025-08-10T11:44:58.000Z","dependencies_parsed_at":"2025-07-06T14:47:25.975Z","dependency_job_id":null,"html_url":"https://github.com/schettino72/rut","commit_stats":null,"previous_names":["schettino72/rut"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/schettino72/rut","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schettino72%2Frut","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schettino72%2Frut/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schettino72%2Frut/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schettino72%2Frut/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schettino72","download_url":"https://codeload.github.com/schettino72/rut/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schettino72%2Frut/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":272704533,"owners_count":24979388,"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","status":"online","status_checked_at":"2025-08-29T02:00:10.610Z","response_time":87,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cli","test-runner","testing","testing-framework","testing-tools","unittest"],"created_at":"2025-08-29T14:54:07.419Z","updated_at":"2025-10-08T14:37:45.115Z","avatar_url":"https://github.com/schettino72.png","language":"Python","funding_links":[],"categories":["Testing Frameworks"],"sub_categories":[],"readme":"# rut - Run Unit Tests\n\n`rut` is a modern and fully-featured test runner for Python's `unittest` framework, with simplicity as a core design goal.\n\n\u003e Sponsored by [asserto.ai](https://asserto.ai)\n\n## Features\n\n- **Blazingly Fast (to type):** `rut` is only 3 characters.\n- Built-in support for async code.\n- Test discovery with keyword-based filtering.\n- Code coverage support.\n\n## Why use `rut`?\n\n### For the `unittest` User: A Modern Upgrade\n\nAre you a fan of the stability and explicitness of `unittest`, but wish you had a better runner experience? `rut` is your drop-in upgrade.\n\n*   **Zero-Config Discovery:** Just run `rut`. No more writing `if __name__ == '__main__':` boilerplate.\n*   **First-Class `asyncio` Support:** `rut` automatically detects and runs `async` tests correctly. No more `asyncio.run()` wrappers.\n*   **Powerful Filtering:** Run exactly the tests you want with simple keyword filtering (`-k \"my_feature\"`).\n*   **Integrated Coverage:** Get a full coverage report with a single flag (`--cov`).\n\n### For the `pytest` User: Simplicity and Power, Reunited\n\nDo you appreciate the power of modern test runners, but find yourself wrestling with the complexity and \"magic\" of third-party frameworks? `rut` offers a compelling alternative, embracing the explicitness of the standard library.\n\n*   **No Magic, Just Python:** `rut` is built directly on `unittest`. There are no hidden hooks, complex fixture systems, or assertion rewriting. Your tests are plain, debuggable Python.\n*   **Familiar, Powerful Features:** Get the features you rely on, like keyword filtering (`-k`), failing fast (`-x`), and seamless `asyncio` support, without the overhead of a large framework.\n*   **A Leaner Dependency Tree:** `rut` is a single, focused tool, not a sprawling ecosystem. Keep your project's dependencies clean and understandable.\n\n## Installation\n\nAdd `rut` as a development dependency to your project:\n\n```bash\nuv add --dev rut\n```\n\n## Usage\n\n```bash\nrut [options] [path]\n```\n\n### Example\n\nTo run all tests in the `tests/` directory that have the word \"feature\" in their name, you would run:\n\n```bash\nrut -k \"feature\"\n```\n\n### Options\n\n| Option | Short | Description |\n|---|---|---|\n| `--keyword` | `-k` | Only run tests that match the given keyword. |\n| `--exitfirst` | `-x` | Exit on the first failure. |\n| `--capture` | `-s` | Disable all output capturing. |\n| `--cov` | | Run with code coverage. |\n| `--test-base-dir` | | The base directory for `conftest.py` discovery. |\n\n### Positional Arguments\n\n| Argument | Description | Default |\n|---|---|---|\n| `path` | The path to the tests to be discovered. | `tests` |\n\n## Configuration\n\n`rut` can be configured via the `[tool.rut]` section in your `pyproject.toml` file.\n\n### `coverage_source`\n\nTo specify the source directories for coverage reporting, use the `coverage_source` key. If not configured, the default source is `[\"src\", \"tests\"]`.\n\n```toml\n[tool.rut]\ncoverage_source = [\"my_app\", \"libs/my_lib\"]\n```\n\n### `warning_filters`\n\nTo add custom warning filters, use the `warning_filters` key. The format for each filter is a string that follows the `warnings.filterwarnings` format: `action:message:category:module`.\n\n```toml\n[tool.rut]\nwarning_filters = [\n    \"error::UserWarning:pydantic\",\n]\n```\n\n### `test_base_dir`\n\nTo specify the base directory for `conftest.py` discovery, use the `test_base_dir` key.\n\n```toml\n[tool.rut]\ntest_base_dir = \"my_tests\"\n```\n\n## Writing Tests\n\n### Basic Tests\n\nFor standard, synchronous tests, you can use the standard `unittest.TestCase`.\n\n```python\nimport unittest\n\nclass MyTest(unittest.TestCase):\n    def test_something(self):\n        self.assertEqual(1 + 1, 2)\n```\n\n### Async Tests\n\nTo write an asynchronous test, you must use `unittest.IsolatedAsyncioTestCase` as the base class for your test case. `rut` will automatically detect and correctly run `async def` test methods within these classes.\n\n```python\nimport asyncio\nimport unittest\n\nclass MyAsyncTest(unittest.IsolatedAsyncioTestCase):\n    async def test_something_async(self):\n        await asyncio.sleep(0.01)\n        self.assertTrue(True)\n```\n\n## Advanced\n\n### Session-Level Setup and Teardown\n\nFor more complex testing scenarios, you may need to run setup code once before any tests start and teardown code once after all tests have finished. `rut` supports this with special, automatically-discovered \"hook\" functions.\n\nTo use this feature, create a `conftest.py` file in your test base directory (usually `tests/`). `rut` will automatically find and execute the following functions if they are defined:\n\n-   `rut_session_setup()`: Executed once before the test session begins.\n-   `rut_session_teardown()`: Executed once after the test session ends, even if tests fail.\n\nBoth of these functions can be synchronous (`def`) or asynchronous (`async def`).\n\n#### Example `conftest.py`\n\n```python\n# tests/conftest.py\nimport asyncio\nfrom my_app.database import connect_db, disconnect_db\n\nasync def rut_session_setup():\n    print(\"Setting up the test database...\")\n    await connect_db()\n\nasync def rut_session_teardown():\n    print(\"Tearing down the test database...\")\n    await disconnect_db()\n```\n\n### Detecting rut\n\nWhen `rut` is running, it sets the environment variable `TEST_RUNNER` to the value `rut`. You can use this in your test code to enable or disable functionality that is specific to the test runner.\n\n```python\nimport os\n\nif os.environ.get('TEST_RUNNER') == 'rut':\n    # Do something specific to rut\n    pass\n```\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschettino72%2Frut","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fschettino72%2Frut","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fschettino72%2Frut/lists"}