#0021 pytestのトライアル

### はじめに
- 普段unit testで使っているpytestについて基本を調べてみました。

### 基本的な使い方
#### 準備
- `pytest`をインストールしておく
- `utils1.py`にはテストしたい関数、`test_utils1.py`にはテストコードを準備した。

```
/
├── utils
│   ├── utils1.py
├── tests
│   ├── test_utils1.py
```

```
[utils1.py]
def add_func(x, y):
    return x + y
```

```
[test_utils1.py]
import sys
sys.path.append("..")
from utils.utils1 import *

def test_add_func():
    a = 1
    b = 3
    result = add_func(a, b)
    assert result == a + b
    assert type(result) == int
```


#### 実行（1テスト）

- `test_utils1.py`では、add_funcの結果の値と型が合うかをテストする。
- `/tests` の階層で`pytest`または`pytest test_utils1.py`を実行する。
- `pytest`で実行すると、階層にあるすべてのテストコードが実行される。

```
/tests ❯❯❯ pytest test_util1.py
========================= test session starts =========================
platform darwin -- Python 3.9.16, pytest-7.4.2, pluggy-1.3.0
rootdir: /Users/kodamakeita/python/genaral/0916/tests
collected 1 item                                                                                                                                                                 
test_util1.py .  [100%]

========================= 1 passed in 0.00s =========================
```

#### 実行（1テスト） fail

- `test_utils1.py`を以下のように変えて失敗を起こしてみる。
- 
```
def test_add_func():
    a = 1
    b = 3
    result = add_func(a, b)
    assert result == a + b +7
    assert type(result) == int
```

```
/tests ❯❯❯ pytest test_util1.py
========================= test session starts =========================
platform darwin -- Python 3.9.16, pytest-7.4.2, pluggy-1.3.0
rootdir: /Users/kodamakeita/python/genaral/0916/tests
collected 1 item                                                                                                                                                                 
test_util1.py F            

========================= FAILURES =========================
_________________________ test_add_func _________________________
    def test_add_func():
        a = 1
        b = 3
        result = add_func(a, b)
>       assert result == a + b +7
E       assert 4 == ((1 + 3) + 7)

========================= short test summary info =========================
FAILED test_util1.py::test_add_func - assert 4 == ((1 + 3) + 7)
========================= 1 failed in 0.02s =========================
```

#### 実行（3テスト）

- テストのファイルが複数あると以下のようになる。
```
/tests ❯❯❯ pytest                                                                        
========================= test session starts =========================
platform darwin -- Python 3.9.16, pytest-7.4.2, pluggy-1.3.0
rootdir: /Users/kodamakeita/python/genaral/0916/tests
collected 3 items                                                                                                                                                                 
test_util1.py .  [ 33%]
test_util2.py .  [ 66%]
test_util3.py .  [100%]

========================= 3 passed in 0.06s =========================

```


### mockを使ったテスト
- 例えば、requetsなど外部から結果を取得する関数のテストをしたいが、実際の通信が使えない（サーバを起動していないなどで）などの理由で、外部のモジュールとは切り分けてテストをしたい場合はmockを使う。
- mockとはハリボテ的なイメージです。

TBA

```
[request_module.py]
import requests

def get_username(id_num):
    url = "http://xxxxxxxx"
    response = requests.get(url=url, params={"id" : id_num})
    response_json = response.json()
    username = response_json["username"]
    return username


def get_usernames(user_ids):
    user_names = {}
    for id in user_ids:
        user_names[id] = get_username(id)
    print(user_names)
    return user_names
```


```
[test_request_module.py]
import sys
sys.path.append("..")
from utils import request_module

def mock_get_username(id):
    return "Hosshey"

def test_get_usernames(monkeypatch):
    monkeypatch.setattr(
        request_module, "get_username", mock_get_username
    )
    inputs = ["001", "025"]
    result = utils2.get_usernames(inputs)
    assert list(result.keys()) == inputs
    assert list(result.values()) == ["Hosshey"]*len(inputs)
```

### 終わりに
TBA