質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

Q&A

4回答

5052閲覧

上手なテスト駆動開発の進め方について

退会済みユーザー

退会済みユーザー

総合スコア0

RSpec

RSpecはRuby用のBDD(behaviour-driven development)フレームワークです。

Ruby on Rails 4

Ruby on Rails4はRubyによって書かれたオープンソースのウェブフレームワークです。 Ruby on Railsは「設定より規約」の原則に従っており、効率的に作業を行うために再開発を行う必要をなくしてくれます。

テスト駆動開発

テスト駆動開発は、 プログラム開発手法の一種で、 プログラムに必要な各機能をテストとして書き、 そのテストが動作する必要最低限な実装を行い コードを洗練させる、といったサイクルを繰り返す手法の事です。

3グッド

12クリップ

投稿2017/02/05 15:25

現在RailsアプリケーションでRSpecを使いながらテスト駆動か初に挑戦しています。

幾つかテストを書いて思ったことを質問させていただきます。
(テストを導入したのはアプリケーションの機能をほとんど実装してからです)

始めからテストをかけない

今回は、実装がほとんど出来ている状態からテストを書いているので、テストコードをメソッドごとにかけるのですが。
本来であれば最初に書くはずだと思います。ですが最初に書いたコードでは、綺麗にメソッド分割できておらず、ほぼベタ書き状態のものが多い気がします。
そこからリファクタリングをして、メソッドの分割、その後、各メソッドのテストコードを記述というのが理想的なような気がします。

###結合テストからするべき?(テスト=>実装の流れならば)
単体テストの場合ではクラス単位、メソッド単位で行うことが多いかと思います。
テストコードの中でクラスやメソッドを呼び出すということは、クラス名やメソッド名の変更、引数の有無など変更できなくなります。(その都度テストコードを書き換えるのならば良いのですが)

なので、結合テスト(ブラウザぽちぽちして、最終に得られる結果を期待するコードを書く)をすると、メソッドの分割や、名前の変更ができるようになるのではないでしょうか?

その後単体テストを記述し、ロジックの部分をリファクタリングするというのが良いのではないかと思います。

皆様の意見を聞かせて頂きたいです。

KiyoshiMotoki, Harinezumi, ucan-lab👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

まずは質問の回答から…

始めからテストをかけない

テストと実際のコードは同時に作成して、同時に育てるが正解だと思ってます。

結合テストからするべき?

単体テスト以下です。
私がやった限り、TDDのテスト用コードは常に更新しまくりです。
ロジック修正したい、テスト用コードも一緒に変えよう…は日常茶飯事です。
ドキュメントをロジックの実装と同時平行で作るのと同じような感じになります。


以下解説

TDDを初めて半年弱のクソザコナメクジです。
ようやく最近自分なりの型や成功事例ができてきて楽しくなってきました。
この体験から、自分の文章で書いてみました。


普段デバッグはどんな感じでされてますか?
私はもっぱらNode.jsなのでconsole.logですが、
質問者さんはRubyなので、開発中やデバッグ中はprintをあっちこっちに仕込んでるんじゃないかと思います。

TDDではそんなダサいことしません。

デバッグ用のprint文はあとで消すので二度手間になります。
でも、テストコードは消す必要がありません。
TDDに慣れれば消す必要がない大量のprint文に守られながら開発する仕組みが構築できます。

テストに慣れない内は大きなブラックボックスを作ってしまい、デバッグ用コードのお世話になるかと思いますが、
デバッグコードが書けないと分かれば工夫してホワイトになるように頑張るしかなくなります。
私も最近はTDDのやり方に少し慣れ、デバッグ用コードを埋め込む事が減ってきました。


さて、ココからが本題です。

ですが最初に書いたコードでは、綺麗にメソッド分割できておらず、ほぼベタ書き状態のものが多い気がします。

確かに最初は何が作りたいのか曖昧な状態なので、難しいかと思います。
こういうメソッドがいいかな?ああいうメソッドがいいかな?戻り値はInt/String/Hash?

こういう心変わりが常に側にあるのがプログラミングで、
より良い方法を思いつく度に、影響範囲をどう管理するのかが課題です。
TDDは常に最新のロジックを保てと、愚直な修正作業を徹底する管理思想です。

まずは非TDDから見ていきましょう。

  1. このメソッドの戻り値はStringだったけど、不便だからHashに変更しよう
  2. 頭で覚えている箇所や、ファイル検索して依存している箇所を書き換える
  3. 全ての箇所の実装が終わる
  4. 単体テストで確認しているとエラー・・・えっ、なんで?
  5. 漏れてる箇所見つけたわ、横並び項目何個あったっけ・・・?
  6. デバッグコードをアチラコチラに仕込んで、不具合を修正
  7. デバッグコードを消し忘れてレビュー時や結合テスト時に見つかって先輩から叱られる

4〜7のコンボなんてあるあr・・・ねーよwwwという感じですが、たまにあるんですよね。
もれなくフラグを回収してきた私としては、規模が大きいシステムや、システムの完成間近になればなるほど泣きを見る確率が上がるんじゃないかなと思ってます。

次にTDDを見ていきましょう。

  1. このメソッドの戻り値はStringだったけど、不便だからHashに変更しよう
  2. 変更箇所や影響範囲を元にテストコードを修正
  3. テストを実行してアサートエラーの出るエラー項目を割り出す
  4. 該当の項目を修正していく

わぁ、リスクが減った!まるで進○ゼミ!!…では終わらないのがTDDです。
TDDの2のコストは決して無視出来ません。
思いついた最善のロジックをソースコードに反映させる前に、テストコードから手を付けなければならない…これは今でも苦痛です。

これが原因でTDD否定派は多数居ます。
大抵4〜7のリスクを軽く見積もっていたり、TDDに夢みすぎで夢破れたりが主な理由だと思います。

TDDは単なるリスクヘッジとして同時並行でドキュメントを作る程度のものであり、
それ以上でもそれ以下でもないって感じですね。
放置しすぎると使えないゴミになるのでメンテが必要な所もドキュメントと似てますね。


上記2点のメリットを享受する為には、
テストは同時並行、もしくは先に作られている必要があります。
対象の実行用コードのクラスの最初のメソッドが完成するまでにはメンテを開始させたいですね。

最近の私はファイルを作ったタイミングで、
testディレクトリから始まる同じディレクトリ構造のファイルを作るように徹底しています。
もちろんテスト対象のファイルがディレクトリ移動する場合は、面倒でもテストファイルも移動させてます。

投稿2017/02/06 11:44

miyabi-sun

総合スコア21158

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Chironian

2017/02/06 12:33

横から失礼します。 > 大抵4〜7のリスクを軽く見積もっていたり、TDDに夢みすぎで夢破れたりが主な理由だと思います。 少なくとも私の場合の主な理由ですが、中々取れないバグは単体テストでは検出できないエラー(複数のモジュール間の不整合)です。なので単体テストを頑張っても仕方がないかなって思いですね。
退会済みユーザー

退会済みユーザー

2017/02/06 14:22

ご丁寧な回答ありがとうございます。 例まで頂いて非常にわかりやすかったです。 > 思いついた最善のロジックをソースコードに反映させる前に、テストコードから手を付けなければならない…これは今でも苦痛です。 この辺はまさに思っていた通りで安心しました。これはやはり皆さん思っているのですね。 その分その後恩恵を受けられるのでしょうけど....。 ありがとうございました。
ky2

2017/02/14 03:52

単体テストは頑張るでいいと思うけどな。 複数のモジュール間の不整合に対応できないから単体テストをゆるくするは本末転倒な気がします。
miyabi-sun

2017/02/14 04:48 編集

http://goyoki.hatenablog.com/entry/20100223/1266939139 私の回答はこの記事の主張に強く影響されています。 (私の考える)TDDで作るテストはCLIで実行出来る簡素なルールブック以上の価値はなく、速度を落とさず開発する為にガバガバな方が良いと考えています。 本音は品質も上げたいのですが、何を作れば良いか定まりきっていない中で欲張って厳格なルールを作って、こんなはずじゃなかった動かない迂回策を使わねば…えっテストこんなに修正すんの!?という負けパターンに陥って辛くなって断念するという失敗を重ねました。 今はガバガバなルールをさっさと作るという方針を打ち立てて動いています。 その作戦に則って考えると、副作用だらけで時間の掛かるテストはしない。 副作用の出る箇所と出ない箇所を分離して副作用のない箇所に絞ってテストを作るのはテクニックとしては有りと考えています。 カバレッジや品質を保証する単体テストや結合テストのフェーズでは、必要に応じて別の機会を設けるべきかと思います。 ただ、簡単でガバガバとはいえルールに全て準拠しているので、何もしないで単体テストに行くよりかは非常に高品質なものが出来るかと思います。
Chironian

2017/02/14 09:10 編集

ymsr5612さん。 「 大抵4〜7のリスクを軽く見積もっていたり」がTDD否定派の見解ではないか?と書かれていたので、少なくとも私はモジュール間不整合の方が4~7より大きなリスクと感じているので、これを回避できない割に工数がかかる単体テストの自動化には否定的との記載です。 単体テスト自体はもちろん否定しません。単体テストを自動化することを否定しています。投入可能な工数は常に限りがありますから、単体テストが必要な時は手動で行い、その自動化の工数は機能テストの自動化に割いた方が全体の信頼性は上がると考えています。 miyabi-sunさん。 リンク先みました。なるほど、私はTDDを誤解していたようです。 TDDで記述する自動テストは信頼性保証テストではないのですね。なるほど。 確かに、ガバガバな自動化テストはコストパフォーマンスは良さそうな印象です。コーディング~デバック工程のアウトプットの信頼性を上げることで正規の単体テストからの手戻りが減り、その結果、全体の信頼性が上がるということですね。(一次不良率を下げることで全体の信頼性が上がると聞きます。) ウォーターフォール型開発には有用な手法と思います。 開発速度命のアジャイル型には適用しない方が良いかも? いや、テスト機能も持つスタブを先に開発すると言う意味ならアジャイル型にも有用かも知れないですね。
ky2

2017/02/24 02:50

Chironianさん。 返信ありがとうございます。 単体テストと機能テストそれぞれ自動化したほうがいいと思いますが潤沢に工数がない以上、「どこをがんばれば何をなしえるか」これに付きますね。私の感覚だと機能テストも紐解けば最小のクラスやメソッドにいきつくのでやはり、自動化するなら単体テストかな。と思ってしまいます。 また、ブラウザーを操作するようなテストも自動化対象と考えています。 機能テストはどうでしょうか。私の中でモジュール間不整合はViewとModelのI/F差異ぐらいしか浮かびませんでした。 Chironianさんの意見を聞けてよかったです。ありがとうございます。
guest

0

こんにちは。

(私は、自動テストはやってますが、テスト駆動開発をやったことはありませんのでその点は差し引いて見て下さい。)

まず、自動テストとテスト駆動開発は混乱しやすいですが、これらは別物です。
自動テストを実装することはたいへん好ましいと思います。ロジックを修正する際の安心感が段違いです。また、リファクタリングを頻繁に実施できるのでソースをきれいに保ちやすいです。
そして、ターゲットのプログラムより先に自動テストを記述するのがテスト駆動開発ですね。

以上を踏まえ、単体テストの自動化についての質問と感じました。
単体テストの自動化は行うべきかどうか? 行うべきならそれはいつか?ですね。

結論としては、私は細かいレベルの単体テストを自動化すると設計変更時の工数が増大するので、原則避けた方が良いと思います。

テストを自動化すると、設計変更しても仕様が変化しないことを保証する場合にたいへん有効です。同じテストであれば何度でも最小の工数で実行できますから。
従って、設計変更して仕様変更が発生しないレベルでテストを自動化すると開発効率が良くなります。
逆に、細かい単位では設計変更すると仕様も一緒に変化する方が多いです。そのような部分についてテストを自動化しても工数ばかり掛かって意味はほとんどないように感じます。

もっとも重要なテストは、顧客へ約束している通りに動作していることを検証する機能テストです。その効率を上げるために有効なことはどしどしやるべきですが、逆に足を引っ張るようなことは避けた方が良いと思います。

投稿2017/02/06 07:33

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/02/06 14:12

ご回答ありがとうございます! 仕様変更を行わない部分の単体テストを実行し、機能テストについて重点的に考えていきます。
guest

0

むしろユニットテストを結合テスト前に実施した方がコードの品質を保ちやすい気がします。

ユニットテストでは、配列の個数や、メソッド名やクラス名を指定したアサーションを行うわけですから、名前の変更や渡される配列の個数が変われば、それでもうテストはエラーになります。

先に結合やってしまうと、人間が見る分にはエラーはでていないが、全然裏側で整合性がとれてなかったみたいな結果になりかねないと思われます。

テストもしょせん人が書くのが、テスト自体が間違っているとか観点が抜けていることはよくありますし、毎回テストを書くことでの恩恵を必ずしも受けられないのがデメリットかと思います。

投稿2017/05/21 18:13

imamoto_browser

総合スコア1161

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

本来であれば最初に書くはずだと思います。ですが最初に書いたコードでは、綺麗にメソッド分割できておらず、ほぼベタ書き状態のものが多い気がします。

そこからリファクタリングをして、メソッドの分割、その後、各メソッドのテストコードを記述というのが理想的なような気がします。

最初の出だしをどうしようか迷いますよね。

最初からメソッド分割することが大事だと思います。TDDの場合、ボトムアップ的に作りたくなりますが、後で分割方法が変わると手戻りが大きいです。

私の場合、テストとのバランスを取ります。

最初の段階は、ラフスケッチのようなコードを書きます。
詳細でなく、呼び出し側でこんなクラスにこんなメソッドがあれはきれいにかけそうという当たりを付けます。このコードはラフスケッチなので、とりあえず捨てます。(これを一気に動作可能な状態にすると、妙に細かい部分があるので、TDDは無理です。)

それに沿って、コアになるモジュールの最小機能から設計します。

例えば、ストレージに文字列を登録するモジュールだったら、文字列を送ったら(実際に登録などせず)正常終了するようなテストを書きます。

あるいは、DBから文字列を取得するというコードであればどのようなキー(もしくはNull)を送っても、DBに問い合わせもせず一定の文字列を返すとかそういったテストです。

大事なのは、内部動作は気にせず、こういうインターフェイスがあったらいいなという考えで作成することです。

これができれは、そこから育てるのはそれほど難しくないと思います。コードを育てるのは手を動かす量が圧倒的に増えるのでコーディングに時間がかかのではないかという恐れがあると思います。

実際は、先ほどラフスケッチと呼んだコードを詳細まで書き上げた場合、すでに動作検証済みの部分の変更を避けるために、悪い設計をした部分のバグフィックスに大量の時間を割くことになります。

これがテストコードも育てるという考えでやった場合、検証済みのコードはテストコードが守ってくれます。変更が必要なテストコードは、テスト項目は変わりません。そのテスト項目がまったく不要になることがあるとすれば、それは初めには思いつかなかった素晴らしい設計を発見したとであり、それこそがTDDの最大の成果ではないでしょうか。

とはいえ、私も追加すべきコードが初めからわかるような単純なものに関してはTDDでは書かないこともおおいです。やはり、必要に応じてということも忘れてはならないことだと思います。

投稿2017/05/22 04:08

iwamoto_takaaki

総合スコア2883

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問