Codecovを使ってカバレッジを計測する

最近[Codecov](https://codecov.io/)というサービスを使ってカバレッジを計測しているのですが、テストをしようというモチベーションが上がる良いサービスだと思ったので紹介したいと思います。

## Codecovとは

[Codecov](https://codecov.io/)について簡単に説明すると、コードのカバレッジを計測し、可視化したりslackに通知したり出来るサービスです。似たようなサービスだと[coveralls](https://coveralls.io/)なんかがあります。

Codevcovはテストされていないコードを行単位で色づけしたり。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/2638ce62-1af9-c49b-01e4-7061d92eb80a.png)

ファイルやディレクトリ単位でカバレッジを計測したり。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/e323a281-0946-c72c-10c5-f219ea819314.png)

GitHubと連携させてプルリクにカバレッジがどう変化したかをコメントしてくれたり。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/b8d66f42-3c7a-15e6-c2a0-4a25121d0869.png)

Slackと連携してカバレッジの差分が閾値を越えたら警告することができます。

<img width="800" alt="codecov.png" src="https://qiita-image-store.s3.amazonaws.com/0/11510/18ee4c7c-ad7d-174d-5035-f174945b9208.png">

カバレッジがとれる言語も幅広く、Java・Ruby・PHP・Python・Goなどメジャーな言語は一通りサポートされますし、サンプルコードも公式のリポジトリで手厚くサポートされています。

https://docs.codecov.io/docs/supported-languages

また設定をymlで書くことが可能で、カバレッジが閾値以下になるプルリクはマージできないようにしたり、結果をSlackなどに通知するための設定を書くことが出来ます。

https://docs.codecov.io/docs/codecov-yaml

基本的なカバレッジを可視化するサービスとしては十分な機能をそろえている言えると思います。

またCodecovの良いところとしてFreeプランでPrivateリポジトリが一つ**無料**で使用できることです。会社で使用するときまずはこの無料枠で試してみて、設定などがこなれてきたら課金して他のリポジトリでも使えるようにするとよさそうです。

## Codecovのはじめかた

PythonでのCodecovのはじめ方を解説していきます。今回はDjangoのアプリケーションでテストをしていきます。

サンプルリポジトリは次のURLです。

https://github.com/nasum/django_todo

### テスト対象のコード

最初にテスト対象のコードを示します。

```python:modules/todo/modesls/todo.py
from django.db import models


class Todo(models.Model):
    text = models.CharField(max_length=255, null=None)
    is_done = models.BooleanField(default=False, null=None)
    created_at = models.DateTimeField(auto_now_add=True)

    @classmethod
    def create(cls, **params):
        return cls.objects.create(**params)

    @classmethod
    def get_list_all(cls):
        return list(cls.objects.all())

    @classmethod
    def get_by_id(cls, id):
        try:
            return cls.objects.get(id=id)
        except cls.DoesNotExist:
            return None
```

Djangoのモデルです。Todoモデルを作成しました。

```python:modules/todo/service/todo.py
from modules.todo.models.todo import Todo


def create(**params):
    return Todo.create(**params)


def get_all():
    return Todo.get_list_all()


def get_by_id(self, id):
    return Todo.get_by_id(id)
```

Todoモデルを操作するサービスモデルです。

```python:/modules/todo/test.py
from django.test import TestCase

from modules.todo import service as todo_sv
from modules.todo.models.todo import Todo


class TodoServiceTests(TestCase):

    def test_create(self):
        todo_sv.create(text='hoge', is_done=False)
        todo_list = Todo.objects.all()
        self.assertEqual(len(todo_list), 1)

    def test_get_all(self):
        todo_sv.create(text='hoge', is_done=False)
        todo_list = todo_sv.get_all()
        self.assertEqual(len(todo_list), 1)
```

サービスモデルをテストするテストコードです。上記のコードだと `create` と `get_all` はテストされていますが `get_by_id` はテストされていません。

この状態でカバレッジを計測すべく準備をしていきます。

### codecovでカバレッジを計測するための準備

codecovを使用してカバレッジを計測していきたいと思います。

まずは実際にカバレッジを計測する`coverage.py`と、codecovに計測結果を送信する`codecov`をインストールします。

```cmd
$ pipenv install -d coverage codecov
```

`coverage.py` はdjangoのテストと一緒に使うことで `.coverage` ファイルを作成します。このファイルはテストのカバレッジ結果が保存されています。

`codecov` コマンドはこのファイルを使用してcodecovに情報を送信します。

カバレッジを計測し、それをcodecovに送る流れをCIに組み込みます。今回はCircleCIを使用して行います。

CircleCIの設定を次に示します。

```yaml:.circleci/config.yml
version: 2
jobs:
  build:
    docker:
      - image: circleci/python:3.7.1
    working_directory: ~/repo
    steps:
      - checkout
      - restore_cache:
          keys:
            - cache-{{ checksum "Pipfile.lock" }}
            - cache-
      - run:
          name: Install dependencies
          command: pipenv sync --dev
      - save_cache:
          key: cache-{{ checksum "Pipfile.lock" }}
          paths:
            - ~/.local
            - ~/.cache
      - run: pipenv run coverage run --source='.' ./manage.py test
      - run: pipenv run codecov
```

CIのステップにカバレッジを計測するステップとそれを送るステップを書いています。

次にトークンをCIにセットします。トークンはcodecovのダッシュボードからプロジェクトを追加するときに閲覧することが出来ます。

<img width="1175" alt="codecov_02.png" src="https://qiita-image-store.s3.amazonaws.com/0/11510/342a4df3-21ec-8acb-818b-67f19ac6aa50.png">

<img width="1136" alt="codecov_03.png" src="https://qiita-image-store.s3.amazonaws.com/0/11510/a436299b-4c80-64e3-e756-53dae0ab87d5.png">

<img width="990" alt="codecov_04.png" src="https://qiita-image-store.s3.amazonaws.com/0/11510/3f599dad-0d76-0347-a01f-2c33e1df7614.png">

ここまで設定してCIを実行するとCodecovでカバレッジ結果を閲覧することが出来ます。

Codecovでは次のように表示されます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/9526c40d-f00f-94b0-18b1-05f00c0f0695.png)

テストされていない `get_by_id` のコードが赤くなっていることが分かります。

これ以降プルリクを投げるたびにプルリクにコメントされ、カバレッジの結果を毎回見ることが出来るようになります。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/11510/affccceb-e94a-96b9-2379-c1978297fa6e.png)

プルリクにはコードの量に応じた大きさの四角が描かれた画像が表示されます。その部分のカバレッジが下がっていると赤く表示されます。今回のプルリクにはメソッドを追加してテストは書いていなかったためカバレッジが下がり赤く表示されることが分かります。

## 可視化されることで上がるテストへのモチベーション

Codecovを使うことでカバレッジをグラフィカルに表示し、プルリクにもわかりやすくコメントを入れてくれることを見てきました。Codecovを使わなくても `coverage.py` を使えば％表示でカバレッジを見ることは出来ますが、グラフィカルに表示することで実際にテストされていないコードを見ることも出来ますし、カバレッジが減っていることも色でわかりやすく表示されます。

また自分の出したプルリクにコメントとしてカバレッジの増減を表示することにより、テストへのモチベーションが上がります。自分出したプルリクに、カバレッジが減少したファイルが赤く表示されたら緑にしたくなる気持ちがわき、テストを書くことが楽しくなるのがポイントです。

とはいえただテストを書くだけでは品質向上には繋がらないので、テストの描き方についてはレビューが必要でしょう。

## まとめ

[Codecov](https://codecov.io/)について簡単に紹介していきました。プルリクへのコメントやFreeプランでprivateなリポジトリが一つ使えるというところが魅力的です。

Codecovでカバレッジを常に計測し十分にテストされたプロダクト開発を行っていきたいところです。