JenkinsとAppiumを用いてpipeline実行する

# はじめに

docker上のJenkinsからpytestを実行し、appiumサーバを用いてモバイルテストのpipeline実行を行う。
Jenkinsの起動はyamlを使用し、Appiumサーバはpythonコード上から実行する。
また、Jenkinsfileの作成例と、pythonコード上からAppiumを起動する場合の使用例を記載する。

# システム概要
![システム構成図.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2787932/dab97369-835e-67f0-a13d-d510e3fac175.png)

# 実行環境
- docker : 20.10.17
- jenkins : 2.373
- appium : 2.3.0
- python : 3.10.4

# 実行方法

## 1.Jenkinsの起動とjobの作成

- dockerデーモンの起動
    ```shell
        $ sudo service docker start
    ```

- jenkinsの起動
    ```shell
        $ cd "docker-compose.yamlまでのパス"
        $ docker-compose up --build
    ```
     *`docker-compose up`時に`--build`オプションを付けないと最新のjenkinsを起動できないため注意。

- jobの作成と設定
    - pipeline jobの作成方法については[こちら](https://tracpath.com/works/development/how_to_create_a_new_job_in_jenkins_2/)のサイト等がわかりやすいため、この記事では詳しいpipeline jobの作成方法は省略する。

        - ただし、pipelineの定義は"Pipeline script from SCM"として、テスト対象のあるリポジトリ、ブランチの指定を行う。
![pipelineの定義.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2787932/62b3892d-b9da-8967-caa6-879ad741c67a.png)

        - "Script Path"の欄にGitにおいたJenkinsfileまでのpathを記入する。
![script_pathの定義.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2787932/d72b7acb-c6cb-b223-a493-6b20a165fdd5.png)


## 2.ノードの起動

- PCをjenkinsのノードとして起動する。
    ```shell
        $ curl -sO http://localhost:[指定したポート番号]/jnlpJars/agent.jar
        $ java -jar agent.jar -jnlpUrl http://localhost:[指定したポート番号]/computer/[ノード名]/jenkins-agent.jnlp -workDir [ワークディレクトリまでのパス]
    ```


## 3.エミュレータの起動

- Android Studioを用いて複数端末を起動する。

- コマンドラインから各端末のUDIDを取得しておく。

    - git bashなどのコマンドラインから以下のコマンドを実行し、UDIDを控えておく。
        ```shell
            $ adb devices
       ```
![list_of_devices.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2787932/15bb94e1-6686-a171-85f4-46c9712289fd.png)
`List of devices`の値がUDIDになる


## 4.実行

- Jenkinsから”ビルドの実行”を実行。

# その他

## Jenkinsfileの作成例
```shell
    pipeline {
        agent {
            node {
                label 'mypc-label' // jenkins上でPCにつけたノードラベル
            }
        }
        stages {
            stage('test') {
                parallel{
                    stage("Android-Pixel-3"){
                        steps {
                            sh '''       
                            export PORT=4723  // Android端末(Pixel3)に紐づくappiumサーバのポート番号
                            export UDID=emulator-hoge  // Android端末(Pixel3)のUDID
                            pytest test_android_hogefuga.py
                            '''
                        }
                    }
                    stage("Android-Pixel-4"){
                        steps {
                            sh '''
                            export PORT=4724  // Android端末(Pixel4)に紐づくappiumサーバのポート番号
                            export UDID=emulator-fuga  // Android端末(Pixel4)のUDID
                            pytest test_android_hogefuga.py
                            '''
                        }
                    }
                }
            }
        }
    }
```

## pythonコードからappiumサーバを起動する
```python
    import os
    
    @classmethod
    def setup_class(cls):
        apk_path = r"テスト対象までの絶対パス" # 相対パスでは動かない
      
        cls.appium_server = AppiumService()
        cls.appium_server.start(args=['-a','localhost', '-p', str(os.environ['PORT'])])
      
        cls.driver = webdriver.Remote(
            command_executor="http://localhost:" + str(os.environ['PORT']) + "/wd/hub",
            desired_capabilities={
                "deviceName": "Android_test", 
                "platformName": "Android",
                "udid": os.environ['UDID'],  # 端末の識別
                "app": apk_path,  # 書き換える
            },
        )
```
# 参考
- https://tracpath.com/works/development/how_to_create_a_new_job_in_jenkins_2/
- https://cocodrips.hateblo.jp/entry/2017/10/23/205801
- https://qiita.com/jun_higuche/items/d53ac5bca922f388ea67