手動テストと自動テスト

# 1.はじめに
+ 今週のテーマ：[ソフトウェアテスト](https://qiita.com/yuyas7/items/582e2d0daf2baa786e84)
+ 今回書くもの：手動テスト、自動テスト
+ あくまで学習記録です。


# 2.本文

### 手動テストと自動テストの比較

|  | 手動テスト | 自動テスト |
|:-:|:-:|:-:|
| 財政的コスト  |  シンプルなものを除いて高価 | ほとんどのプロジェクトでは安価  |
| 人的コスト | 高（通常、QAチームで行われる） | 低（通常、開発メンバーで行われる）  |
| 時間的コスト | 高  | 低  |
| 再利用性 | 低  | 高  |
| エラーの可能性 | 高 | 低 |
| 探索的テストの可否|あり|なし|
|エッジケーステストの実装難易度|高|低|

### 手動テスト(manual test)
+ 自動化ツールやスクリプトを使用せずに手動でテストすること。
+ 長所
・手動テストは必須で、テストケースの最初のセットとして使われる。
・テストケースが少数の場合、効率よく行える。
・エッジケースをチェックするのに便利
・エラーの原因の特定したり、原因を特定したりするのが難しい場合に便利。　ただし、経験則がいるテストになる。
・自動化できない場合は、手動でやることになる。
※エッジケースとは：問題コードのパラメータが限界に達している場合や、プログラムの境界をテストするケースのこと。論理エラーはエッジケースで発生します。

+ 短所
・非常に時間がかかる。
・無秩序になりやすい。テストしたいコードとテストコードが一緒になってしまう。
・モジュール化されていないので、簡単に再利用できない。
・テストケースによるエラーが多い。開発者によるテスト作成ミスなど。
・何百万のエントリや何テラバイトの入力データを用いて、正確なパフォーマンスデータを得ることはできない。

+ 例
閏年を求める関数をテストする。
4の倍数なら閏年
例外として１００の倍数は違う、４００の倍数は閏年
```sample.py
def assertPredicate(predicate):
    assert predicate
    print("Passed the assertion test.")

def isLeapyear(year):
    if year % 100 == 0: return False
    elif year % 400 == 0: return True
    elif year % 4 == 0: return True
    else: return False

def assertionTests():
    assertPredicate(isLeapyear(100) == False)
    assertPredicate(isLeapyear(400) == True) # AssertionError
    assertPredicate(isLeapyear(99) == False)
    assertPredicate(isLeapyear(4) == True)

assertionTests()
```
```
: python3 sample.py
Traceback (most recent call last):
  File "script.py", line 17, in <module>
    assertiontests()
  File "script.py", line 13, in assertiontests
    assertPredicate(isLeapyear(400) == True) # assertionError
  File "script.py", line 2, in assertPredicate
    assert predicate
AssertionError
```
エラーがどこにあるかわかる。
```sample.py
def assertPredicate(predicate):
    assert predicate
    print("Passed the assertion test.")

def isLeapyear(year):
    if year == 0: return False
    if year % 400 == 0: return True
    elif year % 100 == 0: return False
    elif year % 4 == 0: return True
    else: return False

def assertionTests():
    assertPredicate(isLeapyear(0) == False)
    assertPredicate(isLeapyear(100) == False)
    assertPredicate(isLeapyear(400) == True)
    assertPredicate(isLeapyear(99) == False)
    assertPredicate(isLeapyear(4) == True)

assertionTests()
```
```
: python3 sample.py
Passed the assertion test.
Passed the assertion test.
Passed the assertion test.
Passed the assertion test.
Passed the assertion test.
```


### 自動テスト(automatic test)
+ 自動化されたツールやスクリプトを使用してテストすること。
テストケースの実行と結果のチェックが手動の介入をせずに行えること。
単純なシナリオや多数繰り返すことには向いているが複雑なものや予測不可能なものは苦手

+ 長所
・自動で処理することで時間計算量や空間計算量を計算することができる。
・テストケースと入力を手動ではなく、アルゴリズム的に作成できる。
・アルゴリズムの整合性やデータの保証があれば、自動テストによって全ての作業ができる。
・静的な手動テストと異なり、数行のコードでテスト基準のロジックを拡張できる。
・テストを自動化するために、AIや最新のツールを利用できる。

+ 短所
・単発のテストや少数のテストケースの場合は手動テストの方がいい。
・アルゴリズムテストを書く場合は、問題に対する理解が必要。
・探索的テストができない（事前にパラメーターが設定されているから）
・エッジケースなどの特定のデータセットをテストすることができない。
・特定のテストは自動化することはできない。リソースの消費が激しくなる場合がある。

+ 例
```sample2.py
def isLeapyear(year):
    if year % 100 == 0: return False
    elif year % 400 == 0: return True
    elif year % 4 == 0: return True
    else: return False

def leapCheck(num, result):
    return isLeapyear(num) == result

def unitTestCheck(predicate):
    if predicate:
        print("The test passed.")
    else:
        print("Error: The test failed.")
    
def unitTests(inputs, outputs):
    for input, output in zip(inputs, outputs):
        unitTestCheck(leapCheck(input, output))

unitTests([0, 4, 99, 100, 400], [False ,True, False, True, True])
```
```
:python3 sample2.py
The test passed.
The test passed.
The test passed.
Error: The test failed.
Error: The test failed.
```


# 3.所感
# ex.参考資料
+ ChatGPT-3.5
+ [Recursion](https://recursionist.io/)