SonarQubeでpythonのテストカバレッジを出力


# 本記事の内容
* MacでSonarQube構築する手順
* SonarQubeでpythonのunittestカバレッジ出力する手順


# 環境
* docker-compose(本記事ではバージョン 1.23.2)
* Homebrew(本記事ではバージョン 2.0.0)
* python(本記事ではバージョン 3.5.2)

# SonarQube構築手順

## docker-composeでSonarQubeの環境を構築する
* [SonarSourceのdocker-compose.yml](https://github.com/SonarSource/docker-sonarqube/blob/master/recipes/docker-compose-postgres-example.yml)を任意のディレクトリに配備し、docker-composeを起動する

```
$ ls
docker-compose.yml

$ docker-compose up
```

* http://localhost:9000 にアクセスし、以下のような画面が出力されるか確認
![sonarqube1.png](https://qiita-image-store.s3.amazonaws.com/0/136987/947b585e-f53c-f170-4cae-09b640966bed.png)

## Homebrewでsonar-scannerをインストール

* 以下のコマンドを実行し、sonar-scannerをインストールする

```
$ brew install sonar-scanner
```

# SonarQubeでpythonのunittestカバレッジ出力する手順

## SonarQubeの設定

* http://localhost:9000 の画面右上の「Log in」をクリックし、ログインする(id,パスワードは両方とも"admin")

![sonarqube2.png](https://qiita-image-store.s3.amazonaws.com/0/136987/0ca15e7a-b2b2-2959-9984-6de9ff62dc47.png)


* ログインするとtoken名を聞かれるので入力。入力後tokenが発行されるのでどこかに記録しておく。

![sonarqube3.png](https://qiita-image-store.s3.amazonaws.com/0/136987/9093cc4a-61bc-576d-d041-3a0b94df607f.png)


* 主なプログラム言語、OS、プロジェクトキーを聞かれるので入力し、Doneボタンをクリック。その後画面右下の「Finish」をクリック。

![sonarqube4.png](https://qiita-image-store.s3.amazonaws.com/0/136987/64949a80-f958-9b55-89b9-02b6cf23121b.png)



* 画面上部にある「Quality Profiles」をクリックし、一覧からpythonの項目を探してコピーする。コピー時にプロファイル名を聞かれるので入力。

![sonarqube5.png](https://qiita-image-store.s3.amazonaws.com/0/136987/4cbf30ba-8435-e50f-c286-37618320d52a.png)


* 画面上部にある「Rules」をクリック、画面左側に言語一覧が表示されるのでpythonを選択。画面上部の「bulk Change」>「Activate in ...」をクリックし設定を有効にする。以上でSonarQubeの設定は完了。

![sonarqube6.png](https://qiita-image-store.s3.amazonaws.com/0/136987/cbb48ac2-23a0-38ff-4e31-04093afd9876.png)


## pythonカバレッジ出力

SonarPythonはcoverage.pyを使った出力をサポートしている。今回はunittestで出力した結果をcoverage.pyでカバレッジをxml形式で出力し、それをSonarQubeで出力する。


* coverage.pyをインストール

```
pip3 install coverage
```

* 今回は以下のpythonファイルを用意

```
$ ls
test_hoge.py            hoge.py

$ cat hoge.py 
class Hoge:
    def plus(self, a, b):
        return a + b
 
    def minus(self, a, b):
        return a - b

    def multiply(self, a, b):
        return a * b

    def divide(self, a, b):
        return a / b

$ cat test_hoge.py 
import unittest
from hoge import Hoge 
 
class TestHoge(unittest.TestCase):
    def test_plus(self):
        h = Hoge()
        a = h.plus(1, 2)
        self.assertEqual(a, 3)

    def test_minus(self):
        h = Hoge()
        a = h.minus(3, 2)
        self.assertEqual(a, 1)
        
if __name__ == "__main__":
    unittest.main()
```


* 以下のコマンドを実行しカバレッジを出力し、coverage.xmlを作成。

```
$ coverage erase
$ coverage run test_hoge.py 
$ coverage xml -i
```

## sonar-scannerを実行

* pythonファイルのあるディレクトリ内にsonar-project.propertiesを作成。

```
$ ls
coverage.xml			sonar-project.properties
hoge.py				test_hoge.py
```

* 設定は以下のように記載

```
$ cat sonar-project.properties 
sonar.projectKey=sample-test
sonar.sources=. 
sonar.exclusions=**/test_*.py
sonar.host.url=http://localhost:9000 
sonar.login={メモしたtokenを記載}
sonar.language=py
sonar.python.coverage.reportPath=coverage.xml
```

* sonar-project.propertiesのあるディレクトリ内でsonar-scannerを実行。カバレッジ結果が出力される。

```
$ sonar-scanner
```

![sonarqube7.png](https://qiita-image-store.s3.amazonaws.com/0/136987/1d59043e-139e-228d-284c-c28371a3bd3d.png)


# 参考

* [docker-sonarqube/recipes.md](https://github.com/SonarSource/docker-sonarqube/blob/master/recipes.md)
* [SonarQubeでソースコードの静的解析とレビューを自動化してみる(前編)](https://dev.classmethod.jp/ci/sonarqube-source-analytics-1/)
* [Python Coverage Results Import](https://docs.sonarqube.org/display/PLUG/Python+Coverage+Results+Import)