# mimid
[![Build Status](https://travis-ci.org/konradhalas/mimid.svg?branch=master)](https://travis-ci.org/konradhalas/mimid)
[![Coverage Status](https://coveralls.io/repos/github/konradhalas/mimid/badge.svg?branch=master)](https://coveralls.io/github/konradhalas/mimid?branch=master)
[![License](https://img.shields.io/pypi/l/mimid.svg)](https://pypi.python.org/pypi/mimid/)
[![Version](https://img.shields.io/pypi/v/mimid.svg)](https://pypi.python.org/pypi/mimid/)
[![Python versions](https://img.shields.io/pypi/pyversions/mimid.svg)](https://pypi.python.org/pypi/mimid/)
[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)
Modern mocking library for Python.
**⚠️ This project is under heavy development, API could be unstable.**
## Installation
To install `mimid`, simply use `pip`:
```
$ pip install mimid
```
## Quick start
```python
from mimid import mock, every, verify, any, gt
def add(a: int, b: int) -> int:
return a + b
def test_add():
add_mock = mock(add)
every(add_mock).returns(5)
result = add_mock(2, 2)
assert result == 5
verify(add_mock).with_args(any(), gt(0)).called(times=1)
```
## Features
Mimid supports following features:
- easy mock behaviour configuration and verification
- works with classes and plain functions
- fully type hinted - it works with IDE's and type checkers
- clean API - not too much magic
## Why not `mock`?
Python built-in `mock` module is an awesome tool. It's a first choice if you want to mock something in your tests.
However it has a few disadvantages:
- it doesn't work well with modern IDEs (e.g. auto completion) and type checkers
- it's difficult to define different behaviours for different cases
- it allows too much freedom, you can do anything with your mock object, even if you didn't define any behaviour
## Inspiration
Mimid is highly inspired by mocking frameworks from a JVM world, like [mockito] or [mockk].
## Usage
There are 3 simple steps in the `mimid` mocking workflow:
1. [Creation](#creation)
2. [Configuration](#configuration)
3. [Verification](#verification)
Additionally you can use [matchers](#matchers) in both configuration and verification steps.
### Creation
You have to use `mock` function to create your mock object. It works both with classes and functions.
Class example:
```python
from mimid import mock
class A:
def foo(self, param):
pass
class_mock = mock(A)
```
Function example:
```python
from mimid import mock
def foo(param):
pass
function_mock = mock(foo)
```
### Configuration
Before you call your mock (function or method) you have to configure its behaviour. Use `every` with additional
methods (`returns`, `raises`, ...) to define how it should works during your test.
```python
from mimid import mock, every
def foo(param):
pass
function_mock = mock(foo)
every(function_mock).returns(1)
```
You can also specify arguments which should trigger defined behaviour.
```python
from mimid import mock, every
def foo(param):
pass
function_mock = mock(foo)
every(function_mock).with_args(param=2).returns(1)
every(function_mock).with_args(param=3).raises(Exception())
```
If you want to define property behaviour you have to use `prop` function:
```python
from mimid import mock, every, prop
class A:
@property
def x(self) -> int:
pass
class_mock = mock(A)
every(prop(class_mock).x).returns(1)
```
Available configurations:
| Configuration | Description |
| ---------------- | ------------------------------------- |
| `returns` | return given value |
| `returns_many` | return each value from provided list |
| `raises` | raise given exception |
| `execute` | call given callable |
### Verification
At the end of your test you can check if mock was called as expected with `verify`.
```python
from mimid import mock, verify
def foo(param):
pass
function_mock = mock(foo)
... # mock calls
verify(function_mock).called(times=2)
```
You can use the same `with_args` also during verification step:
```python
from mimid import mock, verify
def foo(param):
pass
function_mock = mock(foo)
... # mock calls
verify(function_mock).with_args(param=1).called(times=2)
```
### Matchers
You can use matchers during configuration (`with_args`) and verification (`with_args`, `called`) steps. You can also combine matchers with `|` or `&` and negate it with `~`.
Example:
```python
from mimid import mock, every, verify, gt, lt, gte
def foo(param):
pass
function_mock = mock(foo)
every(function_mock).with_args(gt(0)).returns(1)
result = function_mock(10)
assert result == 1
verify(function_mock).with_args(gt(5) | lt(15)).called(times=gte(1))
```
`capture` is a special matcher - it behaves like `any()` but additionally it
stores given argument in provided slot.
Example:
```python
from mimid import mock, every, slot, capture
def foo(param):
pass
function_mock = mock(foo)
param_slot = slot()
every(function_mock).with_args(capture(param_slot)).execute(lambda: param_slot.value + 1)
result = function_mock(1)
assert result == 2
assert param_slot.value == 1
```
Available matchers:
| Matcher | Description |
| ---------------- | ------------------------------------- |
| `any` | match any value |
| `eq` | match equal value |
| `lt` | match lower value |
| `lte` | match lower or equal value |
| `gt` | match greater value |
| `gte` | match greater or equal value |
| `capture` | capture provided argument |
## Authors
Created by [Konrad Hałas][halas-homepage].
[halas-homepage]: https://konradhalas.pl
[mockito]: https://site.mockito.org
[mockk]: https://github.com/mockk/mockk
Raw data
{
"_id": null,
"home_page": "https://github.com/konradhalas/mimid",
"name": "mimid",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.6",
"maintainer_email": "",
"keywords": "testing mocking",
"author": "Konrad Ha\u0142as",
"author_email": "halas.konrad@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/de/35/26182776ea7b0c1cb970a4c98f47a53414d215b7439e72e157cd13fae938/mimid-0.0.10.tar.gz",
"platform": null,
"description": "# mimid\n\n[![Build Status](https://travis-ci.org/konradhalas/mimid.svg?branch=master)](https://travis-ci.org/konradhalas/mimid)\n[![Coverage Status](https://coveralls.io/repos/github/konradhalas/mimid/badge.svg?branch=master)](https://coveralls.io/github/konradhalas/mimid?branch=master)\n[![License](https://img.shields.io/pypi/l/mimid.svg)](https://pypi.python.org/pypi/mimid/)\n[![Version](https://img.shields.io/pypi/v/mimid.svg)](https://pypi.python.org/pypi/mimid/)\n[![Python versions](https://img.shields.io/pypi/pyversions/mimid.svg)](https://pypi.python.org/pypi/mimid/)\n[![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/ambv/black)\n\nModern mocking library for Python.\n\n**\u26a0\ufe0f This project is under heavy development, API could be unstable.**\n\n## Installation\n\nTo install `mimid`, simply use `pip`:\n\n```\n$ pip install mimid\n```\n\n## Quick start\n\n\n```python\nfrom mimid import mock, every, verify, any, gt\n\ndef add(a: int, b: int) -> int:\n return a + b\n\ndef test_add():\n add_mock = mock(add)\n every(add_mock).returns(5) \n \n result = add_mock(2, 2)\n \n assert result == 5\n verify(add_mock).with_args(any(), gt(0)).called(times=1)\n```\n\n## Features\n\nMimid supports following features:\n\n- easy mock behaviour configuration and verification\n- works with classes and plain functions\n- fully type hinted - it works with IDE's and type checkers\n- clean API - not too much magic\n\n## Why not `mock`?\n\nPython built-in `mock` module is an awesome tool. It's a first choice if you want to mock something in your tests.\n\nHowever it has a few disadvantages:\n\n- it doesn't work well with modern IDEs (e.g. auto completion) and type checkers\n- it's difficult to define different behaviours for different cases\n- it allows too much freedom, you can do anything with your mock object, even if you didn't define any behaviour\n\n## Inspiration\n\nMimid is highly inspired by mocking frameworks from a JVM world, like [mockito] or [mockk].\n\n## Usage\n\nThere are 3 simple steps in the `mimid` mocking workflow:\n\n1. [Creation](#creation)\n2. [Configuration](#configuration)\n3. [Verification](#verification)\n\nAdditionally you can use [matchers](#matchers) in both configuration and verification steps. \n\n### Creation\n\nYou have to use `mock` function to create your mock object. It works both with classes and functions.\n\nClass example:\n\n```python\nfrom mimid import mock\n\nclass A:\n\n def foo(self, param):\n pass\n \nclass_mock = mock(A) \n```\n\nFunction example:\n\n```python\nfrom mimid import mock\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\n```\n\n### Configuration\n\nBefore you call your mock (function or method) you have to configure its behaviour. Use `every` with additional\nmethods (`returns`, `raises`, ...) to define how it should works during your test.\n\n```python\nfrom mimid import mock, every\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\nevery(function_mock).returns(1)\n``` \n\nYou can also specify arguments which should trigger defined behaviour.\n\n```python\nfrom mimid import mock, every\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\nevery(function_mock).with_args(param=2).returns(1)\nevery(function_mock).with_args(param=3).raises(Exception())\n```\n\nIf you want to define property behaviour you have to use `prop` function:\n\n```python\nfrom mimid import mock, every, prop\n\nclass A:\n \n @property\n def x(self) -> int:\n pass\n \nclass_mock = mock(A) \nevery(prop(class_mock).x).returns(1)\n```\n\nAvailable configurations:\n\n| Configuration | Description |\n| ---------------- | ------------------------------------- |\n| `returns` | return given value |\n| `returns_many` | return each value from provided list |\n| `raises` | raise given exception | \n| `execute` | call given callable | \n\n### Verification\n\nAt the end of your test you can check if mock was called as expected with `verify`.\n\n```python\nfrom mimid import mock, verify\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\n\n... # mock calls\n\nverify(function_mock).called(times=2)\n```\n\nYou can use the same `with_args` also during verification step:\n\n```python\nfrom mimid import mock, verify\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\n\n... # mock calls\n\nverify(function_mock).with_args(param=1).called(times=2)\n```\n\n### Matchers\n\nYou can use matchers during configuration (`with_args`) and verification (`with_args`, `called`) steps. You can also combine matchers with `|` or `&` and negate it with `~`.\n\nExample:\n\n```python\nfrom mimid import mock, every, verify, gt, lt, gte\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\nevery(function_mock).with_args(gt(0)).returns(1)\n\nresult = function_mock(10)\n\nassert result == 1\nverify(function_mock).with_args(gt(5) | lt(15)).called(times=gte(1))\n\n```\n\n`capture` is a special matcher - it behaves like `any()` but additionally it \nstores given argument in provided slot.\n\nExample:\n\n```python\nfrom mimid import mock, every, slot, capture\n\ndef foo(param):\n pass\n\nfunction_mock = mock(foo)\nparam_slot = slot()\nevery(function_mock).with_args(capture(param_slot)).execute(lambda: param_slot.value + 1)\n\nresult = function_mock(1)\n\nassert result == 2\nassert param_slot.value == 1\n\n```\n\nAvailable matchers:\n\n| Matcher | Description |\n| ---------------- | ------------------------------------- |\n| `any` | match any value |\n| `eq` | match equal value |\n| `lt` | match lower value | \n| `lte` | match lower or equal value | \n| `gt` | match greater value | \n| `gte` | match greater or equal value | \n| `capture` | capture provided argument | \n\n## Authors\n\nCreated by [Konrad Ha\u0142as][halas-homepage].\n\n[halas-homepage]: https://konradhalas.pl\n[mockito]: https://site.mockito.org\n[mockk]: https://github.com/mockk/mockk\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Modern mocking library for Python.",
"version": "0.0.10",
"split_keywords": [
"testing",
"mocking"
],
"urls": [
{
"comment_text": "",
"digests": {
"md5": "8617a574db024f58d045be24e753d465",
"sha256": "ab28ce47a9ac4012c9186435a9fdac63df04991ace9fc76856e5bfedc16224f1"
},
"downloads": -1,
"filename": "mimid-0.0.10-py3-none-any.whl",
"has_sig": false,
"md5_digest": "8617a574db024f58d045be24e753d465",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.6",
"size": 8997,
"upload_time": "2022-12-21T11:21:14",
"upload_time_iso_8601": "2022-12-21T11:21:14.876240Z",
"url": "https://files.pythonhosted.org/packages/17/7e/7973005e2d4e43db450963dd2b47cc7393a7ad993e117dba9f927d5e8f0b/mimid-0.0.10-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"md5": "ea3421515f6579c0a60aed43e0ae7502",
"sha256": "165542c11de4c803315ccc5518ab934351d82d84fc715040468b018ef65a7c1c"
},
"downloads": -1,
"filename": "mimid-0.0.10.tar.gz",
"has_sig": false,
"md5_digest": "ea3421515f6579c0a60aed43e0ae7502",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.6",
"size": 9343,
"upload_time": "2022-12-21T11:21:16",
"upload_time_iso_8601": "2022-12-21T11:21:16.241622Z",
"url": "https://files.pythonhosted.org/packages/de/35/26182776ea7b0c1cb970a4c98f47a53414d215b7439e72e157cd13fae938/mimid-0.0.10.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2022-12-21 11:21:16",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "konradhalas",
"github_project": "mimid",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "mimid"
}