Slide 1

Slide 1 text

とりあえず抑えておきたい Railsでの「テストの内容」の考えかた Kaigi on Rails 2022 2022/10/22 しんくう@shinkufencer

Slide 2

Slide 2 text

本日しゃべること 2 今回はテストのなかでもテストコードに関して大きく2つに分けて お話します 1. テストコードを書くと何が嬉しいのか? 2. 嬉しいポイントを踏まえた上でどういうことを書くといい の?

Slide 3

Slide 3 text

今回のまえおき ● コードでいくつか具体例を紹介しますが、そちらはRSpecで記述したもの をご紹介します ● いくつかのコードは見ずらい部分もあるので、公開しているスライドをご 参照いただければ幸いです 3

Slide 4

Slide 4 text

テストコードは 書くと何が嬉しいのか? 4

Slide 5

Slide 5 text

そもそもテストコードとは ● 今回は「”開発対象のプログラムコード”に対するテストをプログラムコー ドで書いたもの」をテストコードと呼びます ● テストコードによってテストの実施を自動で行っていく取り組みのことを 『自動テスト』と表現します ● このテストコードを用いる自動テストの性質をとらえると嬉しいポイント が考えやすい 5

Slide 6

Slide 6 text

6 (テストという大きな枠組みの中で自動テストがどういうものかという話において) 自動テストって名前で 開発者がやっているものって 自分たちが考えた通りにソフトウェアは 今もこの瞬間も動いているかどうかを 確かめるという行為である – @t_wada texta.fm「9. The 20th Anniversary of TDD 」の 和田卓人さんの発言より https://texta.pixta.jp/entry/2022/03/10/150000

Slide 7

Slide 7 text

自動テストを用いたテストコードの性質 7 ● 「自分たちが考えたとおり」つまり『自分たちが定義した仕様のとおり』 ● 「今もこの瞬間も動いているかどうか」つまり『実装した直後も新しく違 う機能を追加した直後も動いているかどうか』 ● 未知の不具合を見つけ出すのではなく、既知の部分が問題ないかを 『確かめる(checking)』 『仕様の通りに動いているかどうかをいつでも確かめることができる』のが テストコードを用いた自動テストの性質

Slide 8

Slide 8 text

テストコードを用いた自動テストはどの場面で活きる? 8 この自動テストの「確かめることができる」性質を考えたときに 様々なメリットはあるが、わかりやすいメリットを2つ紹介します。 1. プログラムの動作確認が実装直後に可能 2. 変更を加えた際に変更箇所以外が壊れていない確認(回帰テスト)がいつ でもできる

Slide 9

Slide 9 text

嬉しいポイント① 実装直後の動作確認 9

Slide 10

Slide 10 text

実装直後の動作確認 ● 例えば「ユーザーの名前を編集する画面」があったときに以下の仕様を実 装する場合、テストコードを書かない場合と書いた場合で比較して考えて みます 10 ▼仕様 User.nameのバリデーション 名前が5文字以下はエラー。 ・「めでぃかる太郎」はOK ・「のーと次郎」はエラー

Slide 11

Slide 11 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 11 Controllerの修正 Modelの修正 仕様に沿って Userモデルのnameに Validationを入れよう 開発実装 担当 テストコードを書かない場合… validates :name, length: { minimum: 5 } ▼仕様 User.nameのバリデーション 名前が5文字以下はエラー。 ・「めでぃかる太郎」はOK ・「のーと次郎」はエラー

Slide 12

Slide 12 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 12 Controllerの修正 Modelの修正 エラーのときには 編集ページにとどまるように edit actionを修正しよう 開発実装 担当 テストコードを書かない場合…

Slide 13

Slide 13 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 13 Controllerの修正 Modelの修正 エラーのときにはという エラー文言が出るようにしよう 開発実装 担当 テストコードを書かない場合…

Slide 14

Slide 14 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 14 Controllerの修正 Modelの修正 開発実装 担当 あれ?5文字で入れたけど エラーが何も出ない? 確か仕様では5文字以下で エラーしたよね? 手動テスト 担当 ! テストコードを書かない場合… あれ?なんでだろう? もしかしてControllerに 正しく値が渡ってきてない?

Slide 15

Slide 15 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 15 Controllerの修正 Modelの修正 開発実装 担当 手動テスト 担当 ! 初手の実装誤りを一通り作った後に気づき手戻りが発生! テストコードを書かない場合… しまった! Validateのminimumが5だと 5文字のときはsaveできる! 「:minimum: 属性はこの値より小さな値を取れません。」なので 指定した値自体はvalidationのerrorにならない https://railsguides.jp/active_record_validations.html#length

Slide 16

Slide 16 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 16 Controllerの修正 Modelの修正 実装タイミングでテストコードを書くと… 仕様に沿って Userモデルのnameに Validationを入れよう 開発実装 担当 validates :name, length: { minimum: 5 } ▼仕様 User.nameのバリデーション 名前が5文字以下はエラー。 ・「めでぃかる太郎」はOK ・「のーと次郎」はエラー

Slide 17

Slide 17 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 17 Controllerの修正 Modelの修正 実装タイミングでテストコードを書くと… 仕様に沿ってテストコードを書こう 開発実装 担当 ▼仕様 User.nameのバリデーション 名前が5文字以下はエラー。 ・「めでぃかる太郎」はOK ・「のーと次郎」はエラー 仕様の記述にならって 『nameが「めでぃかる太郎」だと保存できる』 『nameが「のーと次郎」だと保存に失敗する』 というテストコードにしよう

Slide 18

Slide 18 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 18 Controllerの修正 Modelの修正 実装もテストコードも完成! テストコードを実行しよう 開発実装 担当 自動テスト 実装タイミングでテストコードを書くと…

Slide 19

Slide 19 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 19 Controllerの修正 Modelの修正 開発実装 担当 自動テスト ? 実装タイミングでテストコードを書くと… あれ、テストコード間違えちゃったかな…? 『nameが「のーと次郎」だと保存に失敗する』 というテストコードが失敗しました

Slide 20

Slide 20 text

リリース 手動動作確認 Viewの修正 実装直後の動作確認 20 Controllerの修正 Modelの修正 開発実装 担当 自動テスト ! あれ、テストケース間違えちゃったかな…? 実装タイミングでテストコードを書くと… しまった!Validateのminimumは 『この値より小さな値を取れません』だから 5を指定したら5文字のときはsaveできる! 早いタイミングで気付ける! 『nameが「のーと次郎」だと保存に失敗する』 というテストコードが失敗しました

Slide 21

Slide 21 text

実装直後の動作確認 ● 今回のケースだとModelで発生した不具合を早期発見できることによって 問題箇所に早く気付け、他の実装前に気づくことができた ● テストコードを書く・実行するという作業を通して軽微なミスを発見でき るので開発にあたるチーム全体としても効率を上げることができる 21

Slide 22

Slide 22 text

嬉しいポイント② 素早く回帰テストができる 22

Slide 23

Slide 23 text

素早く回帰(リグレッション)テストができる 23 ▼仕様 User.profile_textのバリデーション ・20文字以下はエラー ・数字だけで構成されるとエラー ・最初の文字に数字を使うとエラー ・最後の文字に数字を使うとエラー ・「バカ」が含まれるとエラー ・空白文字だけだとエラー 例) 既にあるユーザのプロフィール文章のバリデーションに  『「nil」という文字列が含まれるとエラー』を追加する 手動テスト 担当 新しいバリデーションが 追加されたのか… ここって誰かが前にもテストし た気がしたけど、同じことでき るかな… 手動だと過去と同じ動きをすることができるとは限らない 作業量がふえるとヒューマンエラーで取りこぼす可能性もある 量が多いからテストの抜けもれが ないようにしないと…

Slide 24

Slide 24 text

素早く回帰(リグレッション)テストができる 24 ▼仕様 User.profile_textのバリデーション ・20文字以下はエラー ・数字だけで構成されるとエラー ・最初の文字に数字を使うとエラー ・最後の文字に数字を使うとエラー ・「バカ」が含まれるとエラー ・空白文字だけだとエラー 例) 既にあるユーザのプロフィール文章のバリデーションに  『「nil」という文字列が含まれるとエラー』を追加する 決められたことをテストコード を通してチェックするだけなら いつでもできます 自動テストであれば物量が増えても素早く確認ができる 機械にチェックをお願いするので抜け漏れがない コードで書かれているので 抜け漏れをすることはありません 自動テスト

Slide 25

Slide 25 text

素早く回帰(リグレッション)テストができる ● テストコードは「その時点では正しく動いていた」や「変更したところで 壊れたということに気づく」ということが得意 ● 手動でも同様のことは可能ではあるが、テストコードのほうが手動よりも 短い時間で、漏れなく実施をすることができる 25

Slide 26

Slide 26 text

テストコードがあると何が嬉しいのか? 26 ● 様々なメリットのうちの2つのメリットを紹介しましたがどちらにも共通 して言えることは「仕様に沿っていない不具合を早期発見できる」という ところ ● 一般的に不具合の発見は遅れれば遅れるほど、修正の範囲が大きくなり労 力がかかる傾向にあるので早く発見できればできるほど不要なコストがか からずすむ 『仕様の通りに動いているかどうかをいつでも確かめることができる』ので 不具合に早く気付け、修正コストを最小限にすることに貢献できるのが 嬉しいポイント

Slide 27

Slide 27 text

何が嬉しいのか?はわかった、が… 27 ● テストコードを書く嬉しさは「仕様通り」ということを確かめることがで きること ● しかしテストコードを書くのも開発者自身になるそのため、よりよく「仕 様通り」を確かめるテストコードを書くのが大事

Slide 28

Slide 28 text

どういうテストコードを書くと 仕様通りに動くことを 確かめることができるのか? 28

Slide 29

Slide 29 text

「仕様通り動く」のテストケースはどう考えるといいか ● 「仕様通り動く」ことのテストコードを書いていくと、愚直に考えるべき テストのケース数が膨大になることがある ● そのため「効率的」かつ「抜け漏れが少ない」テストケースを考えて、そ れらを実施していくことが肝心 ● そのテストケースを考えていく先人の知恵が「テスト技法」 29 テストケースを作成するためのノウハウ「テスト技法」を活用することで 効果的なテストコードが作成できます 今回は基本的かつ使いやすい2種類を紹介します

Slide 30

Slide 30 text

テスト技法を考える上でのお題 30 お題: 年齢を扱うクラスに文字列を生成するメソッド「output_view_text」を作成したい。 生成する文字列は以下の通り ● 0歳から18歳までは「幼年」 ● 19歳から30歳までは「青年」 ● 31歳から130歳までは「壮・老年」 なお、0から130以外のものはエラーとしたい。 なお、メソッドに整数値以外のものが入らないことは事前にチェックされているものとする。

Slide 31

Slide 31 text

ベースとなるクラス ::Plain::Age 31 module Plain class Age def initialize(age_value:) raise ArgumentError, "値が整数ではありません " unless age_value.is_a? Integer @age = age_value end def output_view_text raise StandardError, "値が範囲外です" if @age < 0 return "幼年" if @age <= 18 return "青年" if @age <= 30 return "壮・老年" if @age < 130 raise StandardError, "値が範囲外です" end end end

Slide 32

Slide 32 text

テスト技法① 同値分割法 32

Slide 33

Slide 33 text

同値分割法 - お題をとおして使い方を考える 33 年齢ごとに考えると、人間は0歳から始まる生き物だし 0、1、2、3、4、5、6、7、8、9、10…128、129、130で あとは0ではないときの-1、130を上回る値の131を試してみて 131+2=133パターンの入力値のテストを考えればいいのかな…? お題: 年齢を扱うクラスに文字列を生成するメソッド「output_view_text」を作成したい。 生成する文字列は以下の通り ● 0歳から18歳までは「幼年」 ● 19歳から30歳までは「青年」 ● 31歳から130歳までは「壮・老年」 なお、0から130以外のものはエラーとしたい。 なお、メソッドに整数値以外のものが入らないことは事前にチェックされているものとする。

Slide 34

Slide 34 text

愚直にcontextを書いていく場合 34 context "0歳の場合" do let(:age) { ::Plain::Age.new(age_value: 0) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "1歳の場合" do let(:age) { ::Plain::Age.new(age_value: 1) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "2歳の場合" do let(:age) { ::Plain::Age.new(age_value: 2) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "3歳の場合" do let(:age) { ::Plain::Age.new(age_value: 3) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "4歳の場合" do let(:age) { ::Plain::Age.new(age_value: 4) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "5歳の場合" do let(:age) { ::Plain::Age.new(age_value: 5) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "6歳の場合" do let(:age) { ::Plain::Age.new(age_value: 6) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "7歳の場合" do let(:age) { ::Plain::Age.new(age_value: 7) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end End ## 後略 ### 愚直にやると0から130,-1と131を引数に設定した contextを133個書く必要がある

Slide 35

Slide 35 text

同値分割法 - お題をとおして使い方を考える 35 ● 133個のテストケースの時点で書く量がかなり多い ● コピペを繰り返せば作れることは作れるが書き換えミスが起きたりメンテ ナンスしづらい このときに有効なテスト手法が「同値分割法」

Slide 36

Slide 36 text

同値分割法を利用したテストケース作成 36 1. 提示された仕様から値を意味のあるグループ(同値パーティション)に分 ける。仕様として有効な値のグループを「有効同値パーティション」、無 効な値のグループを「無効同値パーティション」という 2. それぞれの同値パーティションに該当する値から少なくとも1つの値を代 表値として取り、その値を使ったテストケースを作成する 同値分割法の考え方は以下の通り

Slide 37

Slide 37 text

同値分割法を利用したテストケース作成 37 ● 今回のケースでは有効同値パーティションと無効同値パーティションは 以下の5つとなる 0 -1 131 130 19 18 31 30 有効同値 パーティション① 「幼年」 有効同値 パーティション② 「青年」 有効同値 パーティション③ 「壮・老年」 無効同値 パーティション① 下限以下エラー 無効同値 パーティション② 上限以上エラー

Slide 38

Slide 38 text

同値分割法を利用したテストケース作成 38 ● パーティションを表に書き出して、代表値を書き足す。 パーティション名 有効/無効 値の範囲 出力される結果 代表値 幼年 有効 0以上18以下 幼年 5 青年 有効 19以上30以下 青年 27 壮・老年 有効 31以上130以下 壮・老年 50 下限以下エラー 無効 -1以下 なし(エラー) -3 上限以上エラー 無効 131以上 なし(エラー) 200

Slide 39

Slide 39 text

39 context "幼年パターン、 5歳の場合" do let(:age) { ::Plain::Age.new(age_value: 5) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "青年パターン、 27歳の場合" do let(:age) { ::Plain::Age.new(age_value: 27) } it "青年と出力されること " do expect(age.output_view_text).to eq("青年") end end context "壮・老年パターン、 50歳の場合" do let(:age) { ::Plain::Age.new(age_value: 50) } it "壮・老年と出力されること " do expect(age.output_view_text).to eq("壮・老年") end End context "-3歳の場合" do let(:age) { ::Plain::Age.new(age_value: -3) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end context "200歳の場合" do let(:age) { ::Plain::Age.new(age_value: 200) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end 同値分割法をベースにしたテストケース 各パーティションから任意の値を拾い上げて選択している この場合は 「5」「27」「50」「-3」「200」 となる

Slide 40

Slide 40 text

同値分割法を利用したテストケース作成 40 ● 5つのパーティションに該当する範囲をすべてやるのではなく、どれか任 意の一つの値を試すことでその範囲の確認とするのが同値分割法 ● そのため、今回は5つのテストケースに対応することでもともとやろうと していた133ケース以上のケースを5つのケースで要点を確認できる ● 本質的にテストしたいのは「決められた範囲内のパターンごとにちゃんと 処理が意図通り行われるか」というところであり、すべての可能性を網羅 したいわけではないので、同値分割法はその点に着目したもの

Slide 41

Slide 41 text

同値分割法だと見つけにくいもの 41 ● 同値分割法で対応するべきものを減らしたが、この5つのケースだと 実は検知できていない潜在的なエラーがある。先程のコードを改めて見て みる。

Slide 42

Slide 42 text

おわかりいただけるだろうか… 42 module Plain class Age def initialize(age_value:) raise ArgumentError, "値が整数ではありません " unless age_value.is_a? Integer @age = age_value end def output_view_text raise StandardError, "値が範囲外です" if @age < 0 return "幼年" if @age <= 18 return "青年" if @age <= 30 return "壮・老年" if @age < 130 raise StandardError, "値が範囲外です" end end end

Slide 43

Slide 43 text

仕様とそぐわない部分 43 module Plain class Age def initialize(age_value:) raise ArgumentError, "値が整数ではありません " unless age_value.is_a? Integer @age = age_value end def output_view_text raise StandardError, "値が範囲外です" if @age < 0 return "幼年" if @age <= 18 return "青年" if @age <= 30 return "壮・老年" if @age < 130 raise StandardError, "値が範囲外です" end end end この書き方だと「年齢が130」だと文字列を返さず StandardErrorを返却してしまう 仕様の意図に合わない! ※ただしくは @age <= 130にしなければならない

Slide 44

Slide 44 text

44 context "幼年パターン、 5歳の場合" do let(:age) { ::Plain::Age.new(age_value: 5) } it "幼年と出力されること " do expect(age.output_view_text).to eq("幼年") end end context "青年パターン、 27歳の場合" do let(:age) { ::Plain::Age.new(age_value: 27) } it "青年と出力されること " do expect(age.output_view_text).to eq("青年") end end context "壮・老年パターン、 50歳の場合" do let(:age) { ::Plain::Age.new(age_value: 50) } it "壮・老年と出力されること " do expect(age.output_view_text).to eq("壮・老年") end End context "-3歳の場合" do let(:age) { ::Plain::Age.new(age_value: -3) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end context "200歳の場合" do let(:age) { ::Plain::Age.new(age_value: 200) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end テストケースも見返す このテストコードでは壮・老年パターンのテストケースは 50で設定しているため気づくことができない

Slide 45

Slide 45 text

同値分割法だけだと見落とされる部分 45 ● プログラムの多くは「分岐」の重ね合わせであり、その分岐の周りの ヒューマンエラーや認識漏れでバグが生まれるケースが多い ● これを防ぐためにすべての考えうるケースをやってしまうと同値分割法を 取り入れる前の状態にもどってしまう ● そのため同値分割法を拡張して、分岐に関してのケースをカバーし拡張す る手法が「境界値分析」

Slide 46

Slide 46 text

テスト技法② 境界値分析 46

Slide 47

Slide 47 text

同値分割法+境界値分析を利用したテストケース作成 47 1. 同値分割法同様にパーティションを作り、各パーティションから「代表 値」をテストの値として取り上げる 2. 各パーティションの取りうる値の境界を「境界値」とし、テストの値とし て取り上げる 3. 1と2で取り上げた値をもとにテストケースを作成する ● 境界値分析は同値分割したパーティションの値に着目し、順序付け可能な 数値の場合の境界を加える考え方は以下の通り

Slide 48

Slide 48 text

同値分割法+境界値分析を利用したテストケース作成 48 パーティション名 有効/無効 値の範囲 出力される結果 代表値 境界値 幼年 有効 0以上18以下 幼年 5 0,18 青年 有効 19以上30以下 青年 27 19,30 壮・老年 有効 31以上130以下 壮・老年 50 31,130 下限以下エラー 無効 -1以下 なし(エラー) -3 -1 上限以上エラー 無効 131以上 なし(エラー) 200 131

Slide 49

Slide 49 text

同値分割法+境界値分析を利用したテストケース作成 49 パーティション名 有効/無効 値の範囲 出力される結果 代表値 境界値 幼年 有効 0以上18以下 幼年 5 0,18 青年 有効 19以上30以下 青年 27 19,30 壮・老年 有効 31以上130以下 壮・老年 50 31,130 下限以下エラー 無効 -1以下 なし(エラー) -3 -1 上限以上エラー 無効 130以上 なし(エラー) 200 131 代表値はケースに合わせてパーティション内の任意の値をとり 境界値はパーティションの範囲の上限と下限を鑑みて設定 無効パーティションの場合は上限や下限が両方あるとは限らな いので内容に応じて追加する

Slide 50

Slide 50 text

50 context "青年パターン、 30歳の場合" do let(:age) { ::Plain::Age.new(age_value: 30) } it "幼年と出力されること " do expect(age.output_view_text).to eq("青年") end end context "壮・老年パターン、 31歳の場合" do let(:age) { ::Plain::Age.new(age_value: 31) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "壮・老年パターン、 50歳の場合" do let(:age) { ::Plain::Age.new(age_value: 50) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "壮・老年パターン、 130歳の場合" do let(:age) { ::Plain::Age.new(age_value: 130) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "131歳の場合" do let(:age) { ::Plain::Age.new(age_value: 131) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end context "200歳の場合" do let(:age) { ::Plain::Age.new(age_value: 200) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end 境界値分析を用いたテストケース(抜粋)

Slide 51

Slide 51 text

51 context "青年パターン、 30歳の場合" do let(:age) { ::Plain::Age.new(age_value: 30) } it "幼年と出力されること " do expect(age.output_view_text).to eq("青年") end end context "壮・老年パターン、 31歳の場合" do let(:age) { ::Plain::Age.new(age_value: 31) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "壮・老年パターン、 50歳の場合" do let(:age) { ::Plain::Age.new(age_value: 50) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "壮・老年パターン、 130歳の場合" do let(:age) { ::Plain::Age.new(age_value: 130) } it "壮・老年 と出力されること " do expect(age.output_view_text).to eq("壮・老年") end end context "131歳の場合" do let(:age) { ::Plain::Age.new(age_value: 131) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end context "200歳の場合" do let(:age) { ::Plain::Age.new(age_value: 200) } it "エラーになること " do expect { age.output_view_text }.to raise_error(StandardError) end end 境界値分析を用いたテストケース(抜粋) このテストコードでは130と131の 2パターンテストしており、テストが失敗するので if文の記述ミスに気づくことができる

Slide 52

Slide 52 text

同値分割法+境界値分析を利用したテストケース作成 52 ● 全件をテストせずに、一番分岐のメインの部分になる「境界」をケースに 加えることでバグに気づきやすい。 ● 多くのメソッドのテストは入力値に対する結果を測るものなので幅広く応 用することができる これでたくさんのテストケースをこなさなくても、少ないケース 数でちゃんと動くかのチェックはできそうだ! これで大量のテストケースをかかなくてすむ!

Slide 53

Slide 53 text

まとめ 53 ● テストコードを含めた自動テストは『仕様の通りに動いているかどう かをいつでも確かめることができる』という性質がある ● 自動テストは不具合に早く気付け、修正コストを最小限にすることに 貢献できるのが嬉しいポイント ● テストコードを書く際には仕様通りかをチェックできるものを作るの が大事 ● 仕様を確認するテストコードを書くときにはテストケースをつくると きのテスト技法を使うと効率よくケースをつくることができる ● 同値分割法と境界値分析は使いやすい方法なので日頃から頭に入れて おくと便利

Slide 54

Slide 54 text

54 しんくう / shinkufencer   @shinkufencer コード日進月歩 https://shinkufencer.hateblo.jp/ ASTERセミナー標準テキスト|Kouichi Akiyama|note https://note.com/akiyama924/m/m6981810393cd Software Design 2022年3月号|技術評論社 https://gihyo.jp/magazine/SD/archive/2022/202203 ソフトウェアテスト技法練習帳 ~知識を経験に変える40問~ https://gihyo.jp/book/2020/978-4-297-11061-1 Thanks! 参考にしたサイト/書籍など: