試作テスト所感1 テスト結果を全部手動確認はだるい
とりあえず、試作を動作させてみた所感としては、テスト項目を自動で作成し、結果予測を設定してない状態だと必ずNGになるのに、一個ずつ上書きの確認をするのは意味が無いという事でした。
多くの場合は下記の流れで良い気がしました。
-
テスト項目設定を自動で作らせ、結果予測無しでファイルに保存する。
-
テスト項目設定ファイルの内容を全て実行させて、その結果をユーザーの確認無しにCheckResultのExpectedの設定に(仮に?)自動上書きし、テスト項目設定ファイルを更新して保存する。
-
テスト項目設定ファイルを確認して、結果がおかしい所はCheckResultのExpectedの設定を修正、又は値を””にし、テスト項目設定ファイルを更新して保存する
-
プログラムを修正。
-
3で修正したテスト項目設定ファイルで再度テストを実行して、結果がおかしい所を人間が一つ一つ確認する。
とはいえ、毎回、実際の結果で上書きされると、バグの内容で正しい予測設定を上書きされる可能性があるので良くない。基本は一回だけ自動上書きの方法を採用したらどうだろうか?
- テスト自動作成時は"settings"内に空のcheck_resultの辞書を作る。
"check_result": {
}
- テスト実行時に"setting"内に"check_result"が無い場合は結果を確認しない。
- テスト実行時に"setting"内に"check_result"は有るが、中身が空の場合は実際の結果を"expected"に自動で書込む。
- テスト実行時に"setting"内の"check_result"に設定がある場合は、その設定で比較し、OKならスルー。NGの場合はユーザーに確認し、実際の結果で上書きするか確認する。
- "check_result"の比較方法にmax,minは欲しいかも。
ただし、「未満」、「より上」のような書き方も考慮した方が良いのか?
=,<,>,<=,=>のような記号を駆使するような表現? - "user_check_throw"がtrueならNGでもUser確認や上書きをしない。
"check_result": {
"expected":6,
"min":-5,
"max":1111,
"range":"-5<result<=1111.1111",
"user_check_throw": true
}
これで、作って自動テストした瞬間にテスト結果が大量に出来上がる仕様になったわけですね。
そして、テスト結果を確認してまずい所を人間が見つける・・・ここは相変わらず面倒。😓
でも、テスト設定(+結果)を複数人のデバッガーに確認してもらう手もあるわけで。
普段は一項目ずつ動作実行してたのなら、その作業時間はカットできますね。
更に言うと、テキストデータなのでAIにまずそうな所をある程度抽出させる事もできるかもしれません。
ただし、自動テストが終わっても、テストが足りない部分は人間様がテストを追加する必要がありますね。
試作テスト所感2 前と同じ動作をしている事を確認するのがこの機能の主機能かも。
継続的にプログラムを更新する際に結構これは重要で、プログラムにバグがあるのはある程度回避できない。しかし、正常に動作させた時の実際の結果を記録しておけば、プログラムを変更した時に前回との差が分かる。(下記のような例外はたくさんあるが)
・ランダムの数字
・日時
・タイミングで結果が変わる(ゲームとか)
・AI
・複雑系
(所感1とほぼ同じ所感でもあるのだけど、)今回試作を試して、目標自体が変わったのでこの気付きが一番の収穫だったかも。
・テスト条件と結果がテキストで一覧になること。
※テキスト縛りにすると、テキスト以外の型の結果の確認が簡単には出来ない問題がありますね。
しかし、幸いにも型の縛りが強いC#では型の異常が別途出るでしょうし、正常稼働した段階では同等の結果さえ出れば大丈夫でしょう。型の縛りが低いPythonはたまに何らかの問題が出る可能性はあるかもですが・・・。
・テスト結果の正誤が分かる事も重要だが、前回の実行結果との差が分かる事が必要条件。
試作テスト所感3 Publicの関数しかテストできない
あたりまえだけど、外部から操作できないように作られたプログラムが外部からテストできないのはそれはどうにもならない事に気づいた。
テストするときだけPublicにする程度ですかね。
試作テスト所感4 テスト生成も設定にしたい。
テスト生成を関数固定にしてるのはマズそう。
プログラムは無限の種類があるのだから、テスト内容も無限にある。
テストする引数を自動作成する部分は設定でカスタマイズできるべき。
試作テスト所感5 PythonとC#などの言語による型違いにより簡単にはテストできない事もある
言語の特徴に関わるTestはその言語でしかTestしきれない事があるのかも。
まぁ、その言語でTestする関数を作って、その関数を本プログラムで動作させるという手もあるのだけど。😗
試作テスト所感X クラスの扱いが練られてない
元々が外部プログラムを実行=関数的な動作を意識しているので、DLLならクラスを使える事が頭から抜けていました。
-
クラスはインスタンスを作ってからメソッドを実行する2段階構成。(これは仮に対応してみた)
-
インスタンスは複数種類作れるので、インスタンスAのメソッド1→インスタンスBのメソッド1→インスタンスAのメソッド2・・・のような起動もあるかもしれない。
現在の作り(Classの子にmethod)ではこれはできない。 -
外部プログラム実行プログラムがクラスを起動し、クラスのFor文でメソッドぶん回す構造だと、メソッドの結果を実行プログラムが管理したくなった場合、クラスのFor文中から結果を親の実行プログラムに渡すのはちょっと面倒そうかも?(所感3に詳細記述)
{
"test": [
{
"type": "ExecuteProgram",
"settings": {
"argument_names": [],
"argument_types": [],
"arguments": [],
"class_name": "ConfigSettingDiff.HelpEntry",
"program_path": "../../../Tools/diff.dll"
"methods": [
{
"argument_names": ["obj"],
"argument_types": ["Object"],
"arguments": [{"key": "value"}],
"check_result": {
"expected": false
},
"method_name": "Equals"
},
{
"argument_names": [],
"argument_types": [],
"arguments": [],
"check_result": {
"expected": 16495015
},
"method_name": "GetHashCode"
}
]
}
},
試作テスト所感Y そもそも、この企画の想定する外部プログラムを実行するプログラムとは?
題に載せている「外部プログラムを実行するプログラム」ってのは外部プログラムを実行して、その結果は内部メモリのDictionaryデータに名前を付けて格納する仕様にする計画です。(言ってませんでしたが)
内部メモリ{"result1":"value1",・・・} ← result= type指定function(settings)
※ExecuteProgramはtype指定function(内蔵の機能)の一つで、外部のProgramを実行する。
その他に下記のような設定どおりに機能を起動する機能、クリック機能が必要と思ってます。
{
"test1":[
{
"name": "test1-1",
"type": "ExecuteProgram",
"settings": {
"arguments":["arg1","arg2"],
"arg1": "value1",
"arg2": "value2",
"comment":"resultは結果を格納する名前を設定する。",
"result":"result_A"
}
},
{
"name": "test1-2",
"type": "ExecuteProgram",
"condition_list":["result_A = True "]
"settings": {
"arguments":["arg1","arg2"],
"arg1": "value1",
"arg2": "value2",
"comment1":"condition_listは実行条件。",
"comment2":"test1-1,1-2は[]で囲まれており、連続実行する作り。"
}
}
],
"test2":[
{
"type": "ExecuteProgram",
"settings": {
"comment":"結果がDictionaryの場合はDictionaryの中身を内部メモリに格納する。",
"arguments":["arg1","arg2"],
"result":{
"success_savedata_name":"success"
"result_B":"result"
},
"reference":{
"arg1":"result_A",
"arg2":"result_B"
}
}
}
],
"Run_Plan_List":[
{
"type": "RunPlanList",
"settings": {
"comment":"この設定をPlanListと名付けていますが、名前指定で連続実行する事を考えてます。",
"run_plan_list":["test1","test2"]
}
}
]
}
結果をメモリに保存してどうするのかというと、その結果を別の関数の設定で"reference"(参照)できるようにしてしまえば、外部プログラム同士の連携ができます。
さて、このように実行プログラムが結果を管理するなら前回の3がちょっとよろしくなさそうなので、クラスについてはもう少し考える必要がありそう。
3. 外部プログラム実行プログラムがクラスを起動し、クラスのFor文でメソッドぶん回す構造だと、メソッドの結果を実行プログラムが管理したくなった場合、クラスのFor文中から結果を親の実行プログラムに渡すのはちょっと面倒そうかも?(所感3に詳細記述)
試作テスト所感Z 外部プログラムを実行するプログラム=>理想のプログラムテストにできるんじゃないか説
で、この掲題の理想のプログラムテストにできるんじゃないか説です。
-
簡単なテストは前述のとおり
-
複雑なテスト、例えば、複数のプログラムの連携による動作確認はどうするのかというと,
①複数のプログラムを本プログラムで"check_result"無しで起動。
②その動作状態をテストしてOKならtrueを返すプログラムを"check_result":{"expected":true}の設定で起動する😗 -
画面クリックやユーザー入力を要するプログラムの動作確認は本プログラムにクリック機能を元から用意しておけばいいわけで。
①テストしたいプログラムを"check_result"無しで起動。
②クリックやユーザー入力する機能を起動。
③結果を確認するプログラムを"check_result":{"expected":true}の設定で起動する😗
まぁ、何でもアリなわけです。
外部プログラムを実行する機能が優秀であるほどテスト機能も優秀になります。
外部プログラム実行+実行結果確認=理想のプログラムテスト
どうでしょう。僕の考えた最強プログラム感。