mimid


Namemimid JSON
Version 0.0.10 PyPI version JSON
download
home_pagehttps://github.com/konradhalas/mimid
SummaryModern mocking library for Python.
upload_time2022-12-21 11:21:16
maintainer
docs_urlNone
authorKonrad Hałas
requires_python>=3.6
licenseMIT
keywords testing mocking
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # 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"
}
        
Elapsed time: 0.12009s