selenium動作用の基底クラスの例にユニットテストを追加

# selenium動作用の基底クラス 利用例2 
## 概要
[以前の記事](https://qiita.com/snowp/items/fcda8c5d590017858bdb)のクラスを使った[例](https://qiita.com/snowp/items/9f51fd0d4b5b20196872)からさらに追加でを作ってみました。
[seleniumのテスト用のサイト](http://www.selenium.jp/test-site)を使用しています。今回は[新サイト](http://example.selenium.jp/reserveApp_Renewal/)を対象にしています。
今回は作った自動クリプトの単体テストまで実施してみました。

## 必要なもの

* python 3.7.2

ライブラリとして

* selenium
* numpy
* pandas
* openpyxl
* xlrd

ブラウザは

* Chrome

を使用しています。
## 公開場所
[github](https://github.com/snowpff14/seleniumSample)で公開しいます。


## 使い方

1. `data/予約データ2.xlsx`に各入力内容に応じて値を入れてください。
    * 日付については未来日かつ3か月以内でないとエラーになってしまうので５月以降を指定していますが参照時期によってはエラーになってしまうので適宜直してください。
1. `seleniumTestSite2`を実行します。
1. 終了するのを待ちます。`screenShot/reserve`に結果は出力されます。
1. `output/resultFiles` に確認画面の内容が出力される。
1. ユニットテストを実行する場合は`test_seleniumTestSite2.py` を実行する。

## ソースの説明

* `data/予約データ2.xlsx`の一行ずつ登録を行っていく。一つのクラスにまとめているが必要に応じてクラスを分けるなど対応を行います。
    * ユニットテストを実施する都合上クラスの中に処理を記載しています。
    * またテスト用と実際の実行用を切り替えられるように`init`メソッドで使用するファイルを切り替えられるようにしています。
    * 実行結果を格納したパス以下のように設定して起きユニットテストの時に比較できるようにしています。
        ```
        infos=testSideOrder.inputOrder(reserveSheet)

        # 結果を格納

        super().setResultPath(infos)
        ```
    * テストでは以下のように結果を取得し比較を行っています。
        ```
        resultFilePath=seleniumTestSite.getResultPath()
        # 比較用の結果はCSVが1番目、Excelが2番目に格納されている

        actualCSVFile=pathlib.Path(resultFilePath[0])

        actualExcelFile=pathlib.Path(resultFilePath[1])



        # 想定された結果が取得できた時

        resultFilePathCSVExpect=pathlib.Path('unitTest/result/001/宿泊情報_テスト結果.csv')

        resultFilePathExcelExpect=pathlib.Path('unitTest/result/001/宿泊情報_テスト結果.xlsx')

        # CSV ファイルを読み込んで比較を行う

        self.csvFileCompare(actualCSVFile,resultFilePathCSVExpect)

        self.excelFileCompare(actualExcelFile,resultFilePathExcelExpect,'Sheet1')
        ```
* 実行する場合は `python test_seleniumTestSite2.py`で実行できます。
* seleniumを使っての自動テスト以外に画面操作の自動化を行う場合スクリプト自体の品質を保証するために使えるかなと思います。

## 各関数の説明

### テストクラス内のメソッド

* CSVファイル同士の比較 引数で渡したもの同士を比較します。

    ```
    # CSVファイルの比較用

    def csvFileCompare(self,actualFilePath,expectFilePath):

        actualDataSets = pd.read_csv(actualFilePath,dtype='str',encoding='cp932')

        expectDataSets = pd.read_csv(expectFilePath,dtype='str',encoding='cp932')
        actualDataArray=np.asarray(actualDataSets)
        expectDataArray=np.asarray(expectDataSets)
        self.bothNumpyArrayEqual(actualDataArray,expectDataArray)
    ```

* エクセルファイル同士の比較 引数で渡したもの同士を比較します。
 
    ```
    # エクセルファイルの比較

    def excelFileCompare(self,actualFilePath,expectFilePath,sheetName):

        actualDataSets = pd.read_excel(actualFilePath,dtype='str',sheet_name=sheetName)

        expectDataSets = pd.read_excel(expectFilePath,dtype='str',sheet_name=sheetName)

        actualDataArray=np.asarray(actualDataSets)

        expectDataArray=np.asarray(expectDataSets)

        self.bothNumpyArrayEqual(actualDataArray,expectDataArray)
    ```
* pandasのDataFrameの比較 CSV,エクセルの比較を行っている処理で呼び出す

    ```
    # pandasのDataFrameをnumpyのArrayに変換したものを比較する

    def bothNumpyArrayEqual(self,actualData,expectData):

        for index,expect in enumerate(expectData):

            self.assertEqual(expect.tolist(),actualData[index].tolist())
    ```

* ヘッダーを追加してCSV出力 ヘッダーを設定してListからDataFrameを作って出力をしています。

    ```
    # ディレクトリに付与する年月日時分、CSVのヘッダー、エラー情報をまとめている辞書を引数として渡す
    def outPutInfoCSV(self,iniFile,colums,infoDict,csvFileName='OutPutInfo',targetDateHourMinute=datetime.now().strftime("%Y%m%d%H%M")):

        infoDirectry = iniFile.get(

            "files", "infoDirectry") + targetDateHourMinute

        os.makedirs(infoDirectry, exist_ok=True)

        infoDataFrame=pd.DataFrame(columns=colums)

        indexCount=1

        for key,dataList in infoDict.items():

            for data in dataList:

                # キーの情報、各種情報のリストの形でまとめる

                infoList=[key]

                infoList.extend(data)

                infoSeries=pd.Series(infoList,index=colums,name=indexCount)

                indexCount=indexCount+1

                infoDataFrame=infoDataFrame.append(infoSeries)

        errorOutputFileName=infoDirectry+'/{0}.csv'.format(csvFileName)
        infoDataFrame.to_csv(errorOutputFileName,encoding='cp932')

        return errorOutputFileName
    ```
* エクセルの出力 基本はCSVと同じですがエクセルなのでセル幅などを調整しています。DataFrameそのままではいけてないので・・・

```

    # 黒い罫線を返すエクセルのセルに黒で罫線を引きたいときに使用する

    def blackBorderLine(self):

        border = Border(
            top=Side(style='thin', color='000000'),
            bottom=Side(style='thin', color='000000'),
            left=Side(style='thin', color='000000'),
            right=Side(style='thin', color='000000'))

        return border


    # ディレクトリに付与する年月日時分、エクセルのヘッダー、エラー情報をまとめている辞書、各セルの幅を格納したリストを引数として渡す

    def outPutInfoExcel(self,iniFile,colums,infoDict,columSize,csvFileName='OutPutInfo',targetDateHourMinute=datetime.now().strftime("%Y%m%d%H%M")):

        infoDirectry = iniFile.get(

            "files", "infoDirectry") + targetDateHourMinute

        os.makedirs(infoDirectry, exist_ok=True)

        infoDataFrame=pd.DataFrame(columns=colums)

        indexCount=1

        for key,dataList in infoDict.items():

            # キーの情報、各種情報のリストの形でまとめる

            for datas in dataList: 

                infoList=[key]

                dList=list(datas)

                infoList.extend(dList)

                infoSeries=pd.Series(infoList,index=colums,name=indexCount)

                indexCount=indexCount+1

                infoDataFrame=infoDataFrame.append(infoSeries)
        outputFileName=infoDirectry+'/{0}.xlsx'.format(csvFileName)


        # 結果を一度エクセルに出力

        infoDataFrame.to_excel(outputFileName,encoding='cp932')

        # 罫線を引くようの設定

        border = self.blackBorderLine()

        # ヘッダーの色付け

        fill = excel.styles.PatternFill(patternType='solid',

                                        fgColor='87ceeb', bgColor='87ceeb')


        # フォーマットを整える

        targetBook=excel.load_workbook(outputFileName)

        sheet=targetBook.active

        columLength=len(colums)

        for index in range(0,columLength+1):

            # 呼び出し元でカラムのサイズを指定して渡す

            sheet.column_dimensions[get_column_letter(index+1)].width=columSize[index]

        for index,row in enumerate(sheet.rows):

            for cell in row:

                cell.border=border

                if index==0:

                    cell.fill=fill

        targetBook.save(filename=outputFileName)

        return outputFileName

```