pytestのすぐに使えるカバレッジ計測

# カバレッジを計測するには

pytestのテストコードを作ったら、カバレッジを確認しましょう。

pytestのpluginでカバレッジ計測の便利なライブラリがあります。
名前は、「**pytest-cov**」です。

pytest-covの最新情報はこちら参照。
https://pypi.org/project/pytest-cov/

上記サイトにオプションの指定例がいろいろ書いてあります。
知っておくと便利なオプションを選んで、やりたいこと別にコマンドと実行例を記載します。


pytest-covのインストール前に、pytestのインストールから動かし方まではこちらです。
https://qiita.com/kg1/items/4e2cae18e9bd39f014d4



# pytest-covインストール

pipコマンドで簡単に導入できます。

```
pip install pytest-cov
``` 

# フォルダ構成、プログラム
**例**として以下のフォルダ構成、プログラムについての実行結果を記載します。

 - フォルダ構成

  - mainフォルダに コード (テスト対象) を配置

  - testsフォルダに テストコード を配置

  - テストコードのファイル名は test_*.py とするのがお約束


```
study_pytest
 ├─main
 |  ├─ calc.py
 |  └─ say.py
 └─tests
    ├─ test_calc.py
    └─ test_say.py
```

 - コード

```calc.py
class Calc: 

    def __init__(self, a, b):
        self.a = a
        self.b = b

    def add(self):
        return self.a + self.b

    def dif(self):
        return self.a - self.b

    def seki(self):
        return self.a*self.b

    def shou(self):
        if self.b == 0:
            return "Not Devide!"
        else:
            return self.a/self.b
```

```say.py
class Foo:

    def say(self):
        return 'foo'

    def say2(self):
        return 'foo2'

class Hoge:

    def say(self):
        return 'hoge'

    def say2(self):
        return 'hoge2'
```

- テストコード

```test_calc.py
from main.calc import Calc

def test_add_01():
    assert Calc(9,2).add() == 11

def test_add_02():
    assert Calc(-9,2).add() == -7

def test_dif_01():
    assert Calc(9,2).dif() == 7

def test_dif_02():
    assert Calc(-9,2).dif() == -11

def test_seki_01():
    assert Calc(9,2).seki() == 18

def test_seki_02():
    assert Calc(-9,2).seki() == -18

def test_shou_01():
    assert Calc(9,2).shou() == 4.5

def test_shou_02():
    assert Calc(-9,2).shou() == -4.5
```

```test_say.py
from main.say import Foo,Hoge

def test_foo_say():
    assert Foo().say() == 'foo'

def test_foo_say2():
    assert Foo().say2() == 'foo2'

def test_hoge_say():
    assert Hoge().say() == 'hoge'

def test_hoge_say2():
    assert Hoge().say2()== 'hoge2'
```

# カバレッジ計測（実践）

study_pytest のディレクトリ に移動してコマンドを実施します。

カバレッジ取得に関してやりたいこと別に **コマンド**、**出力結果** を記載します。

## コマンドラインでカバレッジを確認したい

- コマンド

```
pytest -v --cov=CODE_DIRECTORY
```

- 実行結果

  - 「Stmts」が実行対象コード全体の行数
  - 「Miss」が網羅できなかった行数
  - 「Cover」がカバレッジ率

```
study_pytest>pytest -v --cov=main
============================= test session starts =============================
platform win32 -- Python 3.6.3, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- c:\users\xxx\appdata\local\programs\python\python36\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\xxx\Documents\python\study_pytest, inifile:
plugins: cov-2.5.1
collected 12 items

tests/test_calc.py::test_add_01 PASSED                                   [  8%]
tests/test_calc.py::test_add_02 PASSED                                   [ 16%]
tests/test_calc.py::test_dif_01 PASSED                                   [ 25%]
tests/test_calc.py::test_dif_02 PASSED                                   [ 33%]
tests/test_calc.py::test_seki_01 PASSED                                  [ 41%]
tests/test_calc.py::test_seki_02 PASSED                                  [ 50%]
tests/test_calc.py::test_shou_01 PASSED                                  [ 58%]
tests/test_calc.py::test_shou_02 PASSED                                  [ 66%]
tests/test_say.py::test_foo_say PASSED                                   [ 75%]
tests/test_say.py::test_foo_say2 PASSED                                  [ 83%]
tests/test_say.py::test_hoge_say PASSED                                  [ 91%]
tests/test_say.py::test_hoge_say2 PASSED                                 [100%]

----------- coverage: platform win32, python 3.6.3-final-0 -----------
Name           Stmts   Miss  Cover
----------------------------------
main\calc.py      14      1    93%
main\say.py       10      0   100%
----------------------------------
TOTAL             24      1    96%


========================== 12 passed in 0.20 seconds ==========================
```


## コマンドラインで網羅できなかったコード行を知りたい

- コマンド

```
pytest -v --cov=CODE_DIRECTORY --cov-report=term-missing
```

- 実行結果

  - 「Missing」が網羅されなかった行番号。

```
study_pytest>pytest -v --cov=main --cov-report=term-missing
============================= test session starts =============================
platform win32 -- Python 3.6.3, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- c:\users\xxx\appdata\local\programs\python\python36\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\xxx\Documents\python\study_pytest, inifile:
plugins: cov-2.5.1
collected 12 items

tests/test_calc.py::test_add_01 PASSED                                   [  8%]
tests/test_calc.py::test_add_02 PASSED                                   [ 16%]
tests/test_calc.py::test_dif_01 PASSED                                   [ 25%]
tests/test_calc.py::test_dif_02 PASSED                                   [ 33%]
tests/test_calc.py::test_seki_01 PASSED                                  [ 41%]
tests/test_calc.py::test_seki_02 PASSED                                  [ 50%]
tests/test_calc.py::test_shou_01 PASSED                                  [ 58%]
tests/test_calc.py::test_shou_02 PASSED                                  [ 66%]
tests/test_say.py::test_foo_say PASSED                                   [ 75%]
tests/test_say.py::test_foo_say2 PASSED                                  [ 83%]
tests/test_say.py::test_hoge_say PASSED                                  [ 91%]
tests/test_say.py::test_hoge_say2 PASSED                                 [100%]

----------- coverage: platform win32, python 3.6.3-final-0 -----------
Name           Stmts   Miss  Cover   Missing
--------------------------------------------
main\calc.py      14      1    93%   18
main\say.py       10      0   100%
--------------------------------------------
TOTAL             24      1    96%


========================== 12 passed in 0.20 seconds ==========================
```



## HTML形式のカバレッジレポートを出力したい

- コマンド

```
pytest -v --cov=CODE_DIRECTORY --cov-report=html
```

- 実行結果

  - tests, mainフォルダと同階層にhtmlcovフォルダが作成されレポートが格納される。

```
study_pytest>pytest -v --cov=main --cov-report=html
============================= test session starts =============================
platform win32 -- Python 3.6.3, pytest-3.4.2, py-1.5.2, pluggy-0.6.0 -- c:\users\xxx\appdata\local\programs\python\python36\python.exe
cachedir: .pytest_cache
rootdir: C:\Users\xxx\Documents\python\study_pytest, inifile:
plugins: cov-2.5.1
collected 12 items

tests/test_calc.py::test_add_01 PASSED                                   [  8%]
tests/test_calc.py::test_add_02 PASSED                                   [ 16%]
tests/test_calc.py::test_dif_01 PASSED                                   [ 25%]
tests/test_calc.py::test_dif_02 PASSED                                   [ 33%]
tests/test_calc.py::test_seki_01 PASSED                                  [ 41%]
tests/test_calc.py::test_seki_02 PASSED                                  [ 50%]
tests/test_calc.py::test_shou_01 PASSED                                  [ 58%]
tests/test_calc.py::test_shou_02 PASSED                                  [ 66%]
tests/test_say.py::test_foo_say PASSED                                   [ 75%]
tests/test_say.py::test_foo_say2 PASSED                                  [ 83%]
tests/test_say.py::test_hoge_say PASSED                                  [ 91%]
tests/test_say.py::test_hoge_say2 PASSED                                 [100%]

----------- coverage: platform win32, python 3.6.3-final-0 -----------
Coverage HTML written to dir htmlcov


========================== 12 passed in 0.44 seconds ==========================
```

### カバレッジレポート
カバレッジレポートのサンプルを以下に記載します。

- htmlcov/index.html
 
![image.png](https://qiita-image-store.s3.amazonaws.com/0/188272/f9960ee6-b55a-fef2-99d6-052a7cdf01df.png)


- htmlcov/main_calc_py.html

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188272/826b949a-55e0-c2b5-a409-68c9541310d4.png)



- htmlcov/main_say_py.html

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188272/1e4c9fac-f279-04c5-7d6d-bde5811765db.png)