Pythonでのファイル入出力チェック｜assertでのTDD

#ファイル入出力チェック
ファイルを開いてそれをバイナリ式にコピーして別のファイルで保存します。
２つの方法でファイルのチェックをするようにしています。
以下のファイルを読み込みます。

```C:HelloClang.c
/*******************************************
     Hello.c
 *******************************************/
#include <stdio.h>

int main(){
	int ii = 0;
	int x = 1;
	int y = 2;
	
	for ( ii = 0; ii++; ii<10 ){
		printf("X × Y = %d\n",x*y);
		x++;
		y++;
	}
	 return 0;
}
```

まず一つ目のソースコードです。
##1) try・・・except・・・finally・・・

```Python:try型
    try:
        """・1・"""
    except FileNotFoundError:
        """・2・"""
    finally:
        """・3・"""
```

#### ・サンプルコード１
```Python:tryExFinally.py
# ========================
#   2020.06.21 ProOJI
#    try-except-finally
# ========================

import io


# ファイルを読み込んでそれを書き込む
#  ついでに読み込んだ文字列を出力
def copy_book(input, output):
    """
    inputファイルから
    outputファイルへ書き込み
    """
    # 戻り値は読み込んだ文字数
    print(output.write(input.read())) # 出力:267


# ここからスタート
if __name__ == "__main__":

    # バイナリーストリームを生成する一番簡単な方法
    book_input = open("/Users/.../.../.../sample/HelloClang.c", "r+b")
    book_copy = open("/Users/.../.../.../sample/COPY_BOOK.c", "w+b")

    # ファイル内容をコピー
    copy_book(book_input, book_copy)
    # 先頭にカーソルを配置
    book_input.seek(0)
    book_copy.seek(0)

    # COPY_BOOK.c が存在しているか確認
    try:
        f = open("/Users/.../.../.../sample/COPY_BOOK.c", "r+b")
    except FileNotFoundError:
        print("COPY_BOOK.c does not exist")
    finally:
        f.close()

    # ファイルが同じものか確認
    assert book_input.read() == book_copy.read()
```

では二つ目のソースコードです。
##2) assertを挿入しテスト駆動を実施
```Python:TDD
assert """.1."""
assert """.2."""
assert """.3."""
```
#### ・サンプルコード2
```Python:assertTDD.py
# ========================
#   2020.06.21 ProOJI
#    assert TDD
# ========================

import io


# ファイルを読み込んでそれを書き込む
#  ついでに読み込んだ文字列を出力
def copy_book(input, output):
    """
    inputファイルから
    outputファイルへ書き込み
    """
    # 戻り値は読み込んだ文字数
    print(output.write(input.read()))


# ここからスタート
if __name__ == "__main__":

    # バイナリーストリームを生成する一番簡単な方法
    book_input = open("/Users/.../.../.../sample/HelloClang.c", "r+b")
    book_copy = open("/Users/.../.../.../sample/COPY_BOOK.c", "w+b")

    # ファイル内容をコピー
    copy_book(book_input, book_copy) # 出力：267
    # 先頭にカーソルを配置
    book_input.seek(0)
    book_copy.seek(0)

    # BytesIO オブジェクトを生成
    book_stream = io.BytesIO()

    # 先頭にカーソルを配置
    book_input.seek(0)
    copy_book(book_input, book_stream) # 出力：267

    book_stream.seek(0)
    book_input.seek(0)

    # テストファイルがあるか確認
    if not book_stream.readable():
        print("book_stream does not exist")
        # エラーコードを戻り値に設定
        exit(1)

    # 読み込みと書き込みは同じかテスト
    assert book_input.read() == book_stream.getvalue(), f"Expected: {book_copy.read()}nGot: {book_stream.getvalue()}"

    # 全て閉じる
    book_input.close()
    book_copy.close()
    book_stream.close()

    # 閉じているかテスト
    assert book_input.closed == True  # 期待値 True
    assert book_copy.closed == True   # 期待値 True
    assert book_stream.closed == True # 期待値 True
```
もしエラーがあると

`Line(++++)`
`assert book_input.closed == +++++`
`AssertionError`
というエラーメッセージが出て
期待値と違うことを知らせてくれます。

#まとめ
####TDDで進めるメリット

- バグが少なくなり
- デバッグの時間が短くなり
- 要件への理解が早まり
- リグレッションテストができる

>リグレッションテストとは
>機能の追加やバグの修正をした際に
修正と無関係な部分を壊していないか
チェックするテスト

####TDDで進めるデメリット

- 慣れ親しんだ開発手法からTDDに切り替えるには時間がかかる
- コーディング時間が伸びる
- テストするのが難しいこともある
- 通常より保守するコード量が増えコードの保守が増える

それぞれの長所・短所をよく考慮すべきと思います。
TDDはソフトウェアの品質を改善するための良い手段なので
上手に活用することで品質向上に役立つと思います。