プログラマーなら単体テスト(UT)も実装しよう
■ このスレッドは過去ログ倉庫に格納されています
おまえらちゃんとテスト作ってる? テストメソッドの名前 どういう単位でテスト実装してるか テストのためにアクセス指定子変える派とリフレクション使う派とどっちが多いのとか 最近糞コードのテスト書いてるから辛い TDDやれとまでは言わんが、せめてテストできるレベルの実装位できるようになって欲しい つかnUnitの使い方すら理解できないクズはプログラマー辞めちまえって思う _, ,_ パーン ( ‘д‘) ⊂彡☆))Д´) >>7 うちの職場にもJUnitとかの使い方が分からないレベルの奴ごろごろいるから悲しいわ なんだよ、このグダグダな流れは.... >>15 きちんと責任とれよ!! うちの職場のオッサン、JUnitの使い方分からないし単体テストとか実装してすらいないのに テスト終わったとか嘘言って糞コードコミットしてくるからマジしねばいいのに リフレクション使ってテスト書くくらいならパッケージプライベートとかアクセスできるようにしておくかなー メイン言語はJavaだけど、JUnitでテスト書くようになってからprivateメソッドはあんまり書かなくなったな パッケージプライベートやprotectedを良く使う メソッド単位でテスト書いたほうが楽だし工数も減るし、リファクタリングとかも捗る気がする こういうやり方って実際どうなの?publicメソッドのテストケースしか書かないのが普通? ちゃんとしたテストコードってのを見た事が無くて、どうやるのがいいかいまだによくわからない Javaだとどうなんだろうね。 Objective-CもGoも、やろうと思えばプライベートメソッド呼べるしな。 >>21 ここを参照。 「プライベートメソッドのユニットテストは書かないもの?」 http://qa.atmarkit.co.jp/q/2784 なお、最初の回答のt_wadaが誰なのか知らなければ、和田卓人でググるとテストに関連する記事とか読める。 プライベートかどうかは関係ない。 テストの目的を考えれば、間違いやすいならば テストを書くということは明らかにわかるはず。 関係ないことないでしょ。 privateに対するテストがあると、リファクタリング邪魔になったり、実装詳細を変更したらテストもメンテする必要がでてきたりする。 基本はpublicに対するテストだけでいいと思う。 それはpublicに対するテストの話だからそうなる。 テストはユニットテストだけではない。 privateのテストがあるとリファクタリングのじゃまになったり 実装詳細を変更した時にメンテをする必要があるが、 それはprivateのテストをしない理由ではない。 privateのテストはリファクタリングのじゃまになったり 実装詳細を変更した時にメンテをする必要があるが、 そのデメリットよりもメリットが上回ればやる勝ちはある。 なお、publicでもリファクタリングじゃまになったり メンテをする必要があったりする。 なぜならば、インターフェースを変える修正もあるからだ。 クラスの粒度がやっぱり大きすぎるのかなぁと感じる プライベートメソッドを別のクラスのパブリックメソッドにしてしまえばこういう悩みはなくなりそう でもクラス分けすぎると古い脳の人が混乱するからって怒り始めるし、むずかしいなぁ ユニットテストは仕様に対するテストのことであって、 リファクタリング(外から見た形は変えずに内部の改善をする)を 行うためためだけに存在するわけじゃない。 つーか、ハードウェアの自己診断テストみたいに考えればいいんだよ。 あれはハードウェア内部のテスト。つまりprivateテストみたいなもん。 ハードウェアの自己診断テストでどんなテストを行なっているかは知らんが、 外からは(LEDや音などで)テスト結果がわかる。 それと同じでpublicのself_test()メソッドを呼び出して、その中にテストコードを書く。 外部から見れば、self_test()が仕様通り(自己診断テストにtrueを返すか?)を確認するだけだし、 ハードウェア内部の自己診断テストは、自己が仕様通りかテストをすればいい。 publicのメソッドを実行すればprivateメソッドは内部で呼び出されるんだから publicメソッドのテストだけをやればいいという考えなら、 それに対して、システムテスト、統合テストを行えば、 publicメソッドは呼び出されるんだから、ユニットテストはいらないんじゃね? という考えも成り立つよなと言いたくなる。 テストはなるべく小さい粒度でやるべき。それは問題は小さい方で解決したほうが コストがかからないから。このあたり前の理由がprivateメソッドのテストにも当てはまる。 粒度が大きすぎるなら、当然小さい粒度でやるべき。粒度が問題なのであって それがクラス内部からしか使わないのであれば、それはテストすべきprivateメソッドということになる。 privateメソッドのテストはユニットテストじゃねーよというのであれば、 じゃあ「ユニットテスト」とは違う名前を付けないといけないねって話になるだけ。 ユニットテストをしないが、それはテストをしないという意味ではない ユニットテストと違う名前、つけていいと思う。例えば自己診断テスト。 Javaマだけどパッケージプライベートにしてテスト書いてる あと、そういう可視性をあげたフィールドやメソッドには、Guavaの@VisibleForTestingアノテーションとかつけたりしてる あとTDDしてないけど、実装とリファクタリング平行しながらテストも書いてるから パブリックメソッドだけに全ケース網羅できるようなテスト書くのはちょっとしんどいってのもある クラスが大きすぎるんだろうけど、細かく分け辛い処理(名前が付け辛い処理)って、 業務系クラスだと結構多くて外に持ってくのしんどいのよね >>32 それもありだとは思う。思うけど言語の機能に依存する。 privateメソッドを呼び出す機能が存在しないと使えない。 あと、privateのテストを行うモジュールとpublicのテストを行うモジュールは分けたほうがいいかもしれない。 publicのテストを行うモジュールはユニットテストの目的通り「外部から見た仕様をテストする」もの。 それに対してprivateのテストを行うモジュールは、内部で使われている一機能をテストするもの。目的が違う。 あとprivateメソッドのテストはメソッド全てに対して行う必要はない。publicでも結局は一緒なのだけど、 テストを行うメリットとデメリットを考え、テストを行うメリットがある場合だけテストすればいい。 全部やってて時間が足りるのならやってもいいけど。 網羅するためにPublicメソッドのテストケースを複雑かつ多種用意するくらいなら、 もっと小さい単位のメソッドで網羅して、パブリックメソッドはパスだけテストするほうがコストはかからないね。 リファクタリングには使えないけど、ぶっちゃけちゃんと作れてたら早々大きなリファクタリングは発生しない。 別にリファクタリングに使えないってこともないんだ。 privateメソッドの仕様が変わらず、 内部だけを修正することもある。 長いprivateメソッドを修正し、そのコードの一部を関数化し、 それを汎用モジュールのpublicメソッドにする。 なんて話だってあるだろう。 最初からちゃんと作るというのは、実際には不可能な話で、 だって成長するわけで、誰だって昔の自分はだめなもんだろう? 重要なのは最初から正解を出すことではなく、 どうやって間違ったものを正しくするまでの 道順を考えることだろう。 >>34 > privateメソッドを呼び出す機能が存在しないと使えない。 ん? そもそもprivateメソッドをテストできるかどうかが、言語依存(あるいは処理系依存)じゃないの? 概念としての「プライベートなクラス」に括り出すのなら、C++でも似たようなことはできるよね。 ライブラリとしてまとめて、exportしなければいい。 >>30 > それに対して、システムテスト、統合テストを行えば、 > publicメソッドは呼び出されるんだから、ユニットテストはいらないんじゃね? > という考えも成り立つよなと言いたくなる。 いや、ならないよ。 まず、ユニットテストと結合テストでは行う時期が違う。 バグは早く見つけられれば見つけるほど、修正コストが小さくて済む。 次に、結合テストはたいていの場合ブラックボックステストで行い、要件ベースでテストケースを作成する。 ユニットテストはホワイトボックステストで、コードベース、あるいは、プログラマの意図でテストケースを作成する。 >>39 だからなに?理由になってないんだが。 時期が違ったからって、統合テストで問題なければ publicメソッドのテストは不要だろ? 要件ベースでテストした時、 コードにバグがあればテストに通らないだろ? 統合テストやればユニットテスト不要じゃん。 >>40 何が言いたいかって、単体テストの時にprivateメソッドをやるかどうかという問題と、単体テストを省略して結合テストをやればいいだろという問題は、全く別問題であるという至極普通なことなんだけど。 全く別問題であるがゆえに、仮に単体テスト時にprivateメソッドのテストしなくてもいいと主張したとしても、それが結合テストをするから単体テストは不要ということにはならない。 というか、privateメソッドのテストをすべきどうかは、単体テストの枠組み内で考慮すべき問題なのに、結合テストを持ち出すお前の方が何を言いたいのかさっぱりわからんわ。 >>41 「結合テストをするからといって、単体テストは不要といういう事にはならない。」って俺が言ってることなんだけど? それと同じで、 「publicテストをするからといって、privateテストは不要という事にはならない。」も成り立つって言ってんの。 >>42 話が微妙に変わってる。もう一回>>30 を読み直してみろ。 単体テストでpublicのテストをすればprivateが呼び出されるからprivateのテストは不要と言うのであれば、結合テストをすればpublicメソッドが呼び出されるから単体テストは不要とも言える、というのがお前の主張。 で、そうは言えないというのが俺の主張。理由は前述の通り。 それに、そもそも単体テストではpublicメソッドのみをテストするのが良いという理由は、privateメソッドはテスト中に呼び出されるから不要だからではない。 >>43 お前の言う理由が理由になってないという話。 例えば行うテストを行う時期が違うことは privateメソッドをテストしない理由にはならない。 単体テストでpublicメソッドのみをテストするのはいいが それはprivateメソッドをテストしない理由にはならない。 privateメソッドをテストするとデメリットが有るが そのデメリットよりも、テストをするメリットが高ければ テストをした方がいい。 要するにテストするかしないかは、そのコードはテストをしなければ バグが出やすいかどうかってだけ。 >>45 テストを行う時期が違うからprivateメソッドのテストをしないとは一言も言ってないが。 privateメソッドのテストをしないというなら、publicメソッドも結合テストでテストされるからしなくていいとも言える、という論理は成り立たないと言ってるんだが。 さらに言えば、俺がすべきでは無いと思ってるのは、privateメソッドをprivateメソッドのままでテストすべきでは無いということ。 更に言うなら、君のprivateメソッドをテストする価値があるならやるべきという立場も否定はしない。俺はやらないが。 俺が否定してるのは、君が俺の立場が間違っているという論拠がおかしいといただそれだけのことだよ。 > という論理は成り立たないと言ってるんだが。 お前皮肉もわからんの? publicメソッド経由でテストしてるから不要と抜かしている馬鹿に対して そんなのは理由にならないと皮肉を言ってるんだが? > privateメソッドをprivateメソッドのままでテストすべきでは無いということ。 じゃあどうするか? 1.privateメソッドを呼び出すだけのpublicメソッドを作る 2.privateメソッド+別の処理を行うpublicメソッドを作る(または利用する) 1はジョークとしか思えない、2はなぜ複雑にしてテストをしないといけないのか? テストはシンプルな状態でやるべき。 そしてなるべく早く、privateメソッドが出来た時点でやるべきだ。 privateメソッドをテストしないの理由を聞いていてわかるのは privateメソッドは外部から呼び出せないから テスト出ないだけ。 その言い訳として、あーだーこーだいってる。 それは俺のセリフ。 俺がprivateメソッドテストをしない理由はないといって それに反論してないだろ? それで話は終わりじゃないか。 >>53 >>25 でしない方がいい理由を書いてるんだが。 君はそれを大した根拠もなく、それは理由にならないとしか言えてないよ。 >>54 いや、だからテストをメンテする必要があるから何なの?って話。 メンテスレばいいだけでしょ? それにそもそもの話がある。 Q. 本当にprivateメソッドのテストをメンテする必要があるか? A. privateメソッドの仕様が変わらないなら、privateメソッドのテストをメンテする必要はない。 Q. publicメソッドのテストはメンテしなくてもいいのか? A. publicメソッドの仕様が変わるなら、メンテする必要はある。 publicでもprivateでも仕様が変わればテストをメンテする必要があるし、 仕様が変わらないのならメンテの必要はないんだよ。 ねぇ、private関数を作るときに、private関数単体でテストしないの? 別にユニットテストとか書くとかいう話じゃないよ。 ステップ実行とかでいいからさ、 関数単位でテストしないの? >>55 工数が増えるからといってそれが何なの、と言ってるようにしか聞こえません。 工数が増えるのは問題ですね。 >>57 テストのための工数を嫌がってるようにしか見えないが? 結論は、t_wadaは馬鹿であるってことでいいのかな。 結論は、t_wadaは馬鹿であるってことでいいのかな。 リファクタリング中に、テストが失敗しないことで正しさを担保できるのに、privateメソッドのテストのせいでテストが失敗し、カオスになる。 publicA()の為にprivateA()を作り、privateA()のテストを書いた。publicB()でもprivateA()をつかいたいけど、ちょっと引数を変更しなきゃ。おっと、テストが失敗しまくるぜ。 でも大丈夫。。。俺らには無限の時間があるし。テスト工数をけちっちゃけちっちゃ駄目だよね。 そもそも論で言うなら、privateメソッドを外部からの呼べる言語の方が少ない訳だから、 privateメソッドをテストすべしというのは最初からおかしいんだが。 なんで理由にならないんだ? privateメソッドのみならず、クロージャとか無名メソッドとか、普通は外部から呼べないよね。 呼べないんだからそれはそのまま単体ではテスト出来ませんねってなるのが普通。 privateメソッドは実装詳細なんだから、そのクラスを実装中に引数が変わったり実現内容が変わったりは よくあること。 publicだって変わることがあるというが、それはprivateと頻度が違う。 そんなにころころpublicのI/Fが変わるとしたら、それは実装のやり方が間違ってるよ。 >>65 意味不明。 > リファクタリング中に、テストが失敗しないことで正しさを担保できるのに、privateメソッドのテストのせいでテストが失敗し、カオスになる。 それはprivateかどうかではなく、 テストしているメソッドの仕様を変えたからだろ publicメソッドでも同じ事あるわ。 リファクタリングのうち単純な「メソッド名の変更」と呼ばれるものであっても テストを修正しないとテストは失敗する。 リファクタリングとはね、システムの挙動を変えない変更であって クラス単体の内部の修正ではないんだよ。 >>69 > そんなにころころpublicのI/Fが変わるとしたら、それは実装のやり方が間違ってるよ。 確かにpublicがワールドワイドでpublicならそうだろうね。 世界中で使われているライブラリのpublicメソッドがころころ変わるわけがない。 だがプロジェクトローカルなpublicメソッドだったらどう? 単にひとつの画面をMVCで作ろうととなって、Modelのメソッドは仕方なく publicにしないといけないが、そのメソッドを読んでいるのは特定の画面のみ。 プロジェクトの開発者が少なければ、ころころ変えても問題無いだろ。 >>70 それこそ意味不明だわ。 既存のprivateメソッドで、より適切な名称を思いついて変えようとする。 その程度のことでさえ、そのprivateメソッドのテストがあるとテストが失敗してしまう。 リファクタリングのことわかってないんじゃないの? >>71 だから変更される頻度が違うって言ってるじゃん。 実装詳細は、公開インターフェイスに比べて変更されやすい。 その都度テストメソッドの修正が必要だとしたら、それこそ改善の足かせになってるよね。 >>72 既存のpublicメソッドで、より適切な名称を思いついて変えようとする。 その程度のことでさえ、そのpublicメソッドのテストがあるとテストが失敗してしまう。 >>73 publicが変更されにくいってのはわかるが privateが変更されやすいとは限らないだろ。 特に関数にするようなものは変更されにくい。 ロジックは書き換えるが、 メソッドは変更されにくいんだよ。 ×メソッドは変更されにくいんだよ。 ○メソッドのインターフェースは変更されにくいんだよ。 たとえprivateであってもな。 >>74 クラス内部の構造を改善するリファクタリングしないの? publicメソッドもprivateメソッド変更されにくいって、それでどうやってリファクタリングするわけ? publicメソッドの仕様を変えれば、それを使っている所もテストコードも変更するのは当然。 でも、それはprivateメソッドのテストを書くべきかどうかとは関係ないよね。 なんか言ってることがループしてるな。 privateメソッドは(一般的に)テストをかけない。 → テストがないから変更しやすい。 → 変更しやすくするにはテストを書かない。 → テストがないもの(書けないもの)は変更しやすい。 → 変更しやすくするにはテストを書かない。 → テストがないもの(書けないもの)は変更しやすい。 → 変更しやすくするにはテストを書かない。 →ループ >>75 君がそうだからってみんなそうであると決めないでよ。 実装詳細はその時の状況によって、容易に変更されうる。そして、通常は外部との結合は 無いのだから気軽に行える。その変更の正しさを担保するのがpublicメソッドのテスト群。 設計の基本は、高い凝集度と低い結合度だ。 本来必要ないのに、privateメソッドの結合度を高めてどうするんだって話だよ。 >>76 > クラス内部の構造を改善するリファクタリングしないの? > publicメソッドもprivateメソッド変更されにくいって、それでどうやってリファクタリングするわけ? リファクタリング=クラス内部の構造だけの修正じゃないぞ? クラス構造そのものやメソッドのインターフェースを変えるリファクタリングもある。 インターフェースを変えるリファクタリング方法が存在するのだから それをprivateメソッドにも同じように適用すればいいだけ。 リファクタリングをちゃんと知ってるのなら、privateメソッドも リファクタリングできるってわかるはずなんだがな? > publicメソッドの仕様を変えれば、それを使っている所もテストコードも変更するのは当然。 > でも、それはprivateメソッドのテストを書くべきかどうかとは関係ないよね。 だからそう言ってるだろ。 メソッドのテストを書くべきかどうかは、publicとprivateは関係ない。 メソッドの使用を変えれば、それを使ってるテストコードも変更するのは当然。 >>78 > 実装詳細はその時の状況によって、容易に変更されうる。 ↓ 君がそうだからってみんなそうであると決めないでよ。 容易に変更されないメソッドもある >>77 ループしてると思ってるのは気のせいだよ。 >>78 > 本来必要ないのに、privateメソッドの結合度を高めてどうするんだって話だよ。 なら結合度を高めなければいいだけ。 クラスにself_testってメソッドを作って、 テストの実行は、クラス自身にやらせれば、 外部からのインターフェースは変えずに privateメソッドのテストを行える。 結局のところメソッドのインターフェースの変更が 変わらなければテストは変えなくていいが、 インターフェースが変わればテストの変更も必要。 これはpublicやprivateは関係ないのに 結びつけようとしているのが間違いなんだよな。 >>82 そうしたら、今度はそのself_testの存在が、実装詳細の変更を阻害する要因になるってのが わからないのかなー。 >>85 なんでprivateメソッドのテストが存在することが前提になってるんだよ。 俺は、そのテストがなければ自由に実装詳細を変えられるって話をしてるんだが。 >>86 阻害しないよ? なぜなら、privateメソッドのインターフェースを 変更しなければ、テストの修正は不要だから。 テストがなければ、コードを書き換えても テストに失敗しない! 全てのテストをなくそう! >>88 privateメソッドを直接テストするコードの存在が、実装詳細の変更を阻害する要因になるってのが理解できないの? なんですべてのprivateメソッドにテストコードを書くって 思い込んでるのさ?(笑) 一部の複雑なコードでいかにもテストが必要だってコードに対して じゃあ、仕様変えないようにきっちり作ってテストしようか。 でも外部からは呼び出さないからprivateでいいよね。 って話だろうが。 >>90 > privateメソッドを直接テストするコードの存在が、実装詳細の変更を阻害する要因になるってのが理解できないの? じゃあ、そのメソッドをpublicに変更しろよ! そうすれば、テストコードあっても、実装詳細の変更を阻害する要因にならないって お前の馬鹿な脳でも理解できるだろ? それpublicメソッドが今回はたまたま外部から呼び出す必要がなかったから privateだったってだけだ。 >>91 だから、そのprivateメソッドのテストの存在が、実装詳細の変更を阻害する要因になるってのが理解できないの? その意味で、publicに対するテストとprivate対するテストでは事情が違うと言ってるのに。 > だから、そのprivateメソッドのテストの存在が、実装詳細の変更を阻害する要因になるってのが理解できないの? お前が言っていた理由は全て否定されてる。 何度言っても、理由が書いてないものは 誰にも受け入れられない。 >>92 いきなり何を言い出すんだよ。 俺はprivateメソッドのテストの是非を語ってるんだが。 >>96 俺はテストが必要かどうかにpublicとprivateは関係ないと 言ってるから、何の問題もないが? >>97 それ(>>92 等)に対する反論がないじゃないか。 publicにしたらテストするのに、 それをprivateに戻したらテストしないって おかしい話だろ。 privateに対するテストがあると、リファクタリング邪魔になったり、 実装詳細を変更したらテストもメンテする必要がでてきたりする。 その理由は、ここに書くには狭すぎる。 >>25 は理由を書くように。 先に反論を書いておこう。 privateに対するテストがあっても、 リファクタリングのじゃまにならない場合や 実装詳細を変更してもテストをメンテする必要がない場合もある。 本人は理由だと思っていたものが 単なる意見だと言われるのは 見てて可哀想だなーw >>99 全然おかしくないよ。 話が発散するからあえて書かなかったが、メソッドから意味のある一部分を取り出して 凝集度の高いクラスにするのは、リファクタリングのテクニックの一つで、最初から そうしましょうと言うことだったら話はこじれなかった。 > 話が発散するからあえて書かなかったが、メソッドから意味のある一部分を取り出して > 凝集度の高いクラスにするのは、リファクタリングのテクニックの一つで、最初から じゃあ、メソッドから意味のある一部分を取り出して、 その部分にテストしてもいいじゃないか? >>105 だからそれがprivateに対するテストだと、実装詳細の変更を阻害する要因になるってのが理解できないの? >>106 リファクタリングの邪魔になる理由 実装詳細を変更したらテストもメンテする必要になる理由。 お前まさか、>>25 にその理由が書いてあったと思ったの? その理由を述べた所で、 それはpublicにも当てはまるねって 言い返されて終わりなんだがw >>107 それで、実装詳細の変更を阻害する要因になる理由は? その理由は、publicだとならないんだよね? publicにあてはまることがprivateにもあてはまってしまうことこそが、実装詳細の変更を阻害す 要因になるってのが理解できないの? うん。 publicとprivateでは事情が違う。何故ならprivateは実装詳細だから。 これで話が通じない人と話すのは骨が折れる。 privateメソッドのテストしたところで、それによって品質が上がるわけじゃないし。 無駄な努力っちゃ無駄な努力だよね。 private テストする派の人は、ホワイトボックステストのテストケースを書くべきだと言ってるの? しない派の人は多分、ホワイトボックステストを、自動テスト対象としてのテストケースとしては書かないといってるだけでしょ? 例えばアサーションなんかはテストケースではないが、テストと言えばテストだ。 テストケースではないホワイトボックステストで、しない派はこれをすべきでないとは言ってない。 デバッグ用のチェックコードを忍び込ませるなとも言ってない(かも知れない)。 ということ? privateメソッドのテストは、テスト対象のクラスのOpen-Closed Principleの原則を破ってしまう。 よってprivateメソッドのテストをしてはならない。 自分は外部非公開メソッドのテスト書いちゃうほうだけど、 多分そういうメソッドが多くなるのは、クラスが大きすぎるのが原因なんだろうなーって思ってる でも実務だと、抽象化しまくってかなり細かいクラスにわけちゃったりすると、 レガシー脳の奴がついてこれないどころか重複コード量産始めるから、難しい気もする 大抵はパッケージとか好き勝手に増やしたりも難しいし、あんまり細かい単位でクラス分け辛い あとクラス外出してDIとかするのは、めんどくさいって言われそうだし で、パブリックメソッドから分岐のある可能性のテストケース全部実装するくらいなら、 プライベートメソッドをパッケージプライベートにして、 メソッド単位でテストケース実装して動作確認するほうがいいかな、って感じに テストを行った成果物として残せるし >>116 抽象化しまくってってのがまた設計に失敗してる臭い でも実際DIできるのに自前でnewする馬鹿いるんだよなぁ。 1メソッドに全機能詰め込む奴とか。 Java系マはピンキリ激しくて大抵キリ側に寄ってるから、PHPerと戦わせると良い勝負しそうなの多い。 privateなメソッドの単体テストがどうしても必要な状況って、メソッドの設計がおかしいんじゃね プライベートメソッドがいっぱいあるようなクラスは多分もうすこし細かい部品に分けたほうが再利用性は上がると思う まぁプライベートなメソッドテストした方が楽な場合はそっちのテストにすればいいと思うよ 結局のところ、正しく動くかの確認を、いかにして簡単かつ確実に行えるかが、いちばんだいじな部分だし リファクタリングでprivateメソッド作ったらテストも作んなきゃいけないのは間違ってる気がする 今日初めてMockツールを使って、どうやってMockを利用するのが楽になるかって考えてて気付いた。 判定処理、計算処理みたいなのを判定クラスとして外に出してあげると、プライベートメソッドを殆ど作らなくてよくなる。 判定クラスは値を設定して結果をテストするって感じにできるし、 publicメソッドになるから、先に挙がってるようなリファクタリングの影響も受けない。 テストの実装とても捗るし、TDDとかやりやすくなる。 さらに、元のクラスは、別クラスに外だしした判定処理をDIするような作りにする事ができ、 UTでは全部mockに置き替えてテストできるようになる。 正しく分岐するか、繰り返し処理が行えているか、などのテストに専念できるようになってこれまた捗る。 てことで、こういう感じな所にたどり着いた。 1. 判定処理や計算処理を行うロジッククラスを設ける(何のロジックか、でクラスを分ける感じ) 2. 分岐や繰り返して値をつめる、みたいな処理がメインのクラスでは、判定や計算を極力実装せず、全部委託する テストのしやすい設計って、こういう感じに部品化していく事なんかな。 いままでもっと大きな塊のクラスに処理を纏めようとしてたから、プライベートなメソッドのテストしたくなってたのかも…。 publicメソッドを変更したらどうするんだ? privateメソッドだって変更するんだろ? 変更しないのならprivateメソッドだって変更しないだろうし。 DAOとかentityを使ったクラスのテストってどうしてます? 自動テストするためには、対象テーブルにデータがないといけないので、 テストの時に、データをインサート→テスト→データを削除 とかやってますが、 正直面倒臭いですしどこまでやればいいのかわかりません。 あと、マスタ系はある前提でいいのかとか、 マスタ系もテストデータを挿入する必要があるのかとか、 データがバッティングしてはまずいので、 別スキーマを用意する必要があるのかとか。 また、テーブル変更の際に、エンティティだけの修正で済むのに、 テストデータが古い定義のままなので、 単体テスト動かそうとするとテストデータの修正が必要になったりだとか。 DBが絡んだ途端、JUnitのメリットが半減するような気がします。 そのテストに意味が無いと言うつもりはないが、 データベース使ったら単体にならないだろ? それにテストしたい対象は何だ? データベースなのか? それとも自分が作った部分なのか? テストは全ての部分に対してやる必要はない。 極限まで単純な機能にして、 そこに不具合が入り込む可能性が 少なくなったらやらなくてもいいんだよ。 >>127 データベースを操作するクラスなのに、正しくそれが行われるかどうかをテストしなくて単体テストって呼べるのか? >>126 俺がやっている方法。 基本的なマスタは存在するのが前提としてテストコードを書く。 テスト用のデータベースは個人ごとに持つ。 テストはsetUpでトランザクションを開始し、tearDownでロールバックする。それで大丈夫なように、直接データベースを操作するクラスではコミットはしないようにする。 テストの前提となるデータの準備はコードでやる。 大量のデータが必要な場合は、CSVで準備しデータベースのロード機能を使う。ただしこの場合は、スキーマの変更があったときにCSVの修正が必要になる。 テスト用データベースを構築するスクリプトはバージョン管理する。 スキーマを変更するのも全てスクリプトで行い、そのコミットにはテストでロードするCSVファイルの変更も含める。 こうすればテスト用データベースはいつでもクリーンな状態なので、普通は誰かが使っているテスト用データベースをダンプして自分用のデータベースを作れば良い。 >>128 > データベースを操作するクラスなのに、正しくそれが行われるかどうかをテストしなくて単体テストって呼べるのか? データベースを操作する部分は、実際にはライブラリだろ? データベース操作ライブラリの作者であれば、 実際にデータベースを使ってテストしないといけないが、 そうではないのであれば、データベースを使わない。 クラス と データベース、2つのものが出てきてるのでこれは”単体”ではない。 つまり単体テストが目的なら、データベースの部分をモックに置き換えろって話。 >>129 例えば集計を実行するメソッドがあって、そのソースがデータベースだったとき、自分が実装した選択条件等が正しいかどうかはいつテストするんだ? MVCで言うと、Mはデータベースと接続してテストする方がいいでしょ。 というか、繋げないと妥当性が検証できない場合が多いと思うんだが。 >>129 理想はそうだと思うけど、モックを作るのが無理な人の方が多いから、実際にDB操作を行うテストになるんだと思う 渡される値が何か、みたいなのを知る事ができない人は多い まあ、DBが単なるデータストレージにしか過ぎない場合はmockでもいいけど、 大抵はビジネスロジックがクエリで表現されることが多い。その場合には、 単体テストでDBに繋げろってことだ。 ビジネスロジックのメソッド内からDAOのメソッドを呼ぶとするなら、 ビジネスロジックのメソッドの単体テストではDAOのモックを使い、 DAOのメソッドの単体テストではDBにアクセスするではダメ? SQLがビジネスロジックなら、 SQLのテストを行えばいいのだよ。 アプリは不要。 RDMBSにつないで、SQL実行して そのSQLが期待した通りの答えが帰ってくるか テストすればいい 俺は極論かどうかには興味が無い。 言っていることが正しいかどうかだけだ。 >>135 コードで動的にクエリを組み立てたりしないの? >>134 だから、クエリそのものがビジネスロジックになる場合の話だよ。 そんなこと無いの? >>139 条件を元に動的にクエリが正しく組み立てられるか。 簡単なテストだな。 >>140 その場合の単体テストは、 クエリのテストだよ。 クエリがビジネスロジックを満たしているか 調べればいいだけじゃない。 SQLとRDBMSがあればテストできる。 >>142 クエリが正しいかどうかを最も低コストに検証するのは、実際に動かしてみること。 なんでコードを動作させるのを頑なに拒むの? >>144 なんでそこまで実行を遅延させるんだよ? 意味がわからん。 >>143 だからデータベースに接続して、 そのクエリを流して、 想定通りのデータが帰ってくるか テストをすればいいじゃん? アプリ経由でクエリを流す必要はないよ。 そのクエリはアプリケーションで使うんだろうが? 何を言ってるんだ? きっちりかっちりやるなら単体テストとしてはそっち(DBはDB、アプリはアプリ)の方がいいとは思う DBに依存したテストをやるのは単体というより結合だから、自動実行のために用意するのとはちょっと毛色が違う ローカルで手動実行する結合してみてテストするための補助ツール的な物だと思う クラスを作成するための支援としての単体テストや、自動テストとしてやるものとはちょっち違う感 まぁどっちが楽かはケースバイケースだと思うから、明確に線引く必要はないと思うけど 副作用を目的とするメソッドの単体テストは、何をどこまで確認すべきか。 >>148 例えばあるメソッドにたいして、条件によってクエリが何十パターンにもなる場合、いちいちクエリを出力して、データを投入してデータベースのツールで動作させて、結果を目視で確認したりするの? 何でそんなに手間も時間も間違う可能性もあるようなことするのかさっぱりわからん。 それに、データベースと接続するのを結合まで伸ばす人って、負荷テストはどこでやるの? 因みに俺の場合は、単体で正しく動くことが確認できたらすぐやるよ。 その結果いかんでは、実装の見直しが入るかもしれないから。 FWやORMが出力するレベルのModelやDAOしか必要なければ、別にDBに繋げなくても良い ttp://d.hatena.ne.jp/cero-t/20111210/1323457069 レベル2から3に進めたあたりで世界が変わった気がする 確かに過剰コードはテストデータの準備に時間かけすぎてこれは効率悪いなって感じることが多かった プライベートな処理の可視性をあげてテストを書くとかでケースは大幅に減らせるんだけど、それも少し違うかなって感じてた でも、そもそもクラス設計時点でテストをしづらくしていた事が原因だった >>154 むしろ実装に入ってからじゃ遅すぎる感もあるな 設計とかに影響が出るレベルの検証なんかは設計段階で実施してる 確認したい内容を試すだけの使い捨てコードをちゃちゃっと用意して問題としている部分が大丈夫か試す 設計と実装の線引き自体が環境や人によってまちまちで曖昧な表現だから、タイミングとしては同じことかもしれないけどな んで、そういうのの動作確認のためにユニットテストツールをつかう事はあるけど(実行楽だし)、 それを自動実行するためのコードとしてコミットしたり、今後も保守したりは考えたくないな 検証は検証でそれで終わりで、確認がとれたらちゃんとしたちゃんとした実装を始める感じ >>153 えとさあ、だったらのその問題はどうやって解決できるのさ? クエリにビジネスロジックが入っているって話だよ? クエリが何十パターンにもなるというなら、ビジネスロジックも 何十パターンもなると君はいってるわけだよ? 君は、条件で何十パターンにもなるようなもののテストを どうやってるのさ? これはもはやクエリは関係ない話だ。 データベースに接続するタイミングをどこに持ってくるかはプロジェクトの性格によると思うよ。 俺は自社Webサービスを少数人でやってるけど、スキーマが結構変わるから実際にデータベースと 接続する自動ユニットテストが無いとやってけないからやってる。 >>154 > それに、データベースと接続するのを結合まで伸ばす人って、負荷テストはどこでやるの? アプリが出来上がるまで待つのか? アプリの一部、クエリがわかった時点でやればいいじゃないか。 >>158 問題って具体的に何? 何十パターンにもなるもののテスト方法なら、クエリが絡まない場合と同じだよ。 問題は、そのクエリが妥当なものかどうかを検証する方法で、それはデータベースと 接続して確認するのがいいってことなんだけど。 >>160 いやだから俺はそうしてるわけで、データベースと接続するのを結合まで伸ばす人たちは どうしてるのかなって疑問。 >>162 データベースだけを使ってやるテストは単体テストだよ? かみ合わない話の原因は、DBクエリがラップされてるか自前でSQL書いてるかの違いもあると思う。 個人的には、複雑なビジネスロジックをSQLで実装すること自体をなるだけ避けたい。 業務的な仕様変更に対する修正コストが大きくなるから、引継ぎとか考えると割とダルい。 パフォーマンスへの影響がどれくらいあるか次第だけど、 大きく影響しないと言い切れる部分であれば無理複雑なロジックをSQLで表現しないようにしてる。 単体の話題というよりは設計な気もするけど、まぁTDDなんかは設計の話だし、いいよね。 >>163 でも、データベースにアクセスするコードをデータベースと接続するのは結合テストなんでしょ? >>165 普通の単体テストって テストコード → テスト対象クラス だよね? 同じように テストコード → データベース これも単体。 >>166 別にそれは否定しない。 つか、君、俺に何を言いたいの? 今の流れを纏めると、DBの動きはテスト対象外だからmockに置き換えるよ派と、 クラス内で作ったクエリが正しく動くかも一緒に検証するため、DB操作も含めたUTにするよ派の違い、ってとこかな? 前者は、DBにクエリを投げるクラスの単体なんだから、UTはクエリが想定どおりかをテストするべきだって主張で、 後者は、クエリにビジネスロジック絡んでるから、クエリ生成のあとDBの動作まで含めてUTツールで動作させたいって感じ。 以下私見 クラス単体テストって意味だと、DB部分はMock化すべきで、DBクエリが正しいかを検証するほうが正しいと思う。 なぜなら、DBクエリによるデータ操作結果をテストするのは、DBの動作を検証するDBの単体テストになるから、 言ってしまえばやるべき必要のないケース。テスト工数を嵩ませる要因になってしまうと思う。 内容にもよるけど、そこを頑張ると、テストデータの用意だったり改修に伴う影響だったりで、メンテが辛くなる重たいテストになってしまう。 本来DBに投げるクエリは命令文であって、処理を行うものとは少し違うんだけど、 インラインで別の命令を含めたり、その結果で分岐するようなクエリもかけてしまうせいで、クエリを複雑化しやすい。 なので、クエリを呼び出すクラスでデータベースの動きまで含めてテストにしたいというのは理解できなくもない。 でもあくまでもそれは単体テストではなく、結合テストの自動化だと思う。 他のUTとは別のものとして管理を行ったほうがいいんじゃないかな。 そもそもとして、動的にクエリが変わるうえ、それがビジネスロジックを含むとか大分魔界な感あるw 人間が体感できないほどの実行時間差しか生まなそうな場合は、 複数回クエリを投げてプログラム上で処理したほうが、後々の事を考えるといいケースもあるし、 頻繁にDBを絡めたUTを書かないといけないような事はないと思う。 どうしてもロジックを含むクエリが必要な場合も、1つのクエリに詰め込むよりプロシージャー化するとかしたほうが、 長期的にみるいいんじゃないかな。キッチリやるのはコストかかるから、プロジェクトの規模とかにもよると思うけれど。 >>154 ,162 そもそも、あなたの定義した、 > データベースと接続するのを結合まで伸ばす人たち がどこに居るのかがわからない。 敵を作り出しては居ないかい? ちゃんと作るならDBをモックにすべきって思うけど、 ロジックの全パターンテストしようとすると、 結局DBの返り値想定を何パターンも用意しなくちゃいけなくて、 むしろDB使うより効率悪い気がする。 >>168 だから、きちんと目的の結果を得ることができるクエリを組み立てられたかどうかを 確認するのが目的だってば。 これを結合テストと言いたがる理由がわからない。 あと、テストが必要なのは大抵は一覧を取得するクエリ。 一覧を取得するクエリは、一度のクエリで全部終わるのが理想だから、内容が複雑になりがち。 まあ、Oracle SQLパズルに登場するようなクエリをいくつか合わせたようなイメージ。 >>168 > クラス単体テストって意味だと、DB部分はMock化すべきで、DBクエリが正しいかを検証するほうが正しいと思う。 結局そのクエリの正しさを検証するには、そのシステムで使用しているDBMSを使う必要が ある訳だが?現実的に、そこをわざわざ別のテストにするメリットはあるの? 例えば、Redmineのチケット一覧ページ。 あれが実際どう実装してるのかしらないけど、まあ最終的に単一のクエリが生成されると思ってくれ。 ユーザが指定する条件で、そのクエリのwhere句が変わるのはわかると思う。 それに付け加えて例えば「管理ユーザが登録したもの」とか「直近1週間にSCMに コミットされたもの 間違えて書き込みしてしまった。 とかの条件が加わると、別テーブルもjoinする必要がでてくる。 あるいは、カラムリストにcaseを使う必要が出てくるかもしれない。 そんなクエリをコードで動的に生成するから、それが妥当なものかどうかを単体で 検証したいということ。 で、それを確認するのが最も簡単なのが、DBを使うこと。 なんか、単体テストとか結合テストとか頭硬い人多いな その時点で最もやりたいことを最も低コストでできる手段を使えばいいんだよ mockがいいならmockでいいし、DBに繋げた方がいい人は繋げればいい ただそれだけだよ ステップ実行がいいという人までいるくらいなんだし 仕様通り動くことが確認できれば手段は何でもいいってことだな 単体テスト段階で仕様(要件)とマッチしていることも確認できればいいんだが、 大抵はプログラマの意図通りかを確認するテストになり、仕様とのずれが後工程で 発覚したりする。 条件からクエリを生成する機能をテストするために、SQL文法チェッカ探すよりDBつないだ方が手軽だから、DBを使って単体テストを書く。 というのは別に誰も否定してないだろう。 その機能を実装してる時に、テストケースとは別に DB につないでデバッグしたり、テストコードを紛れ込ませることも、誰も悪いとは言ってない。 自動テスト対象のテストケースとして書く必要はないが、単体テストと並行して普通のデバッグとして DB アクセスしたらいい。 書いてすぐにそこの部分の結合テストしたいなら、前倒しにするなり、実装直後に部分的な結合テストをするようにスケジューリングすればいい。 DB につながないと分からないことが、とかそういうのは単体テストじゃない。 別にこのスレでその話をして悪いとは思わないが、スレタイは単体テストだ。 >>180 > DB につながないと分からないことが、とかそういうのは単体テストじゃない。 なんでそういうことにしたいの? DBUnitとかは全否定? >>180 > というのは別に誰も否定してないだろう。 というのであれば、そのメソッドをリファクタリングしたり、仕様変更等の理由で修正したり、 クエリそのものをリファクタリング(結果が変わらないよりよいクエリに変更すること)をする 時に、自動テストのテストスィートが存在することのメリットがわかると思うけど。 >>168 > どうしてもロジックを含むクエリが必要な場合も、1つのクエリに詰め込むよりプロシージャー化するとかしたほうが、 一つのビジネスロジックを実現するために、複数のSELECT/INSERT/UPDATE/DELETEを組み合わせる必要が有る場合、それらをまるごとストアド化するとカバレッジが取れなくなる。 カバレッジ測定出来ないからストアド禁止ってこと? それはさすがにアホすぎるかと >>183 そうではなくて、ストアドでやってもクライアント言語側でやってもあまりかわらないなら、クライアント言語側で実装すればカバレッジを取れるということ。 また、ストアドで実装すると、バージョン管理が面倒になるというのもデメリット。 それと、これはそれほどたいした話ではないが、一般にストアドよりクライアント言語の方がデータの取り回しが楽。 DBにアクセスするメソッドを呼ぶメソッドのテストではmockを使うのが良い。 DBにアクセスするメソッドのテストでは、データベースに接続するのが良い。 ってことでしょ。かみ合ってないわ。 もともと、動作を確認するのにアドホックなテスト書くくらいだったらxUnitでテスト書こうぜって のりのはずだったのに、DBアクセスだとアドホックなことしたがる理由がわからない。 画面ポチポチで動作確認するのだるい処理をテストするのには向いてるし クラス単体のテストを行ったって結果がとても重要だから、UTの実装もできない連中はクズだと思うよ実際 ちょっとツールの使い方を学ぶ、ってことすらできなくなってる C++でデストラクタのテストはどうすればいいんですかね? 戻り値返せないし、例外も飛ばせないし。 テスト時だけ検証用のコードを入れてますか? テストが必要なほどの処理をデストラクタでやるのが問題な可能性も カバレッジ100%のため、ってことなのかもしれないけど C++殆どやってないし、テストとか書いたことないからよく知らないんだけど 他に影響を与える処理ならモックつっこんで、自身の状態を変えてるなら継承(できるんだっけ?)して 期待した処理が呼ばれるかをテストするとか…? 説明不足ですみません。 良い例では無さそうだけど、こんなクラスでちゃんとfclose()が 成功したか調べる場合どうしたらスマートなのかと思い質問させて頂きました。 class xxx { FILE *fp; public: xxx() {fp = fopen("xxx","r");} ~xxx() {fclose(fp);} }; >>193 モックからチェックするのは思いつきませんでした。 ありがとうございました。 fclose()の戻り値拾って標準エラー出力にでも吐けば? デストラクタの中の処理を関数化して それをテストするとか? フーターズコンテストジャパンで二位だったSerinaが、 黒人に輪姦されてる動画が流出したようですね。 鮮明だし最後は狂ったように泣きながらイキまくってる。 ちんこたった。 http://subject24.xyz/black025.jpg 自動化の単体テストってさ ・難しい箇所 ・壊れやすそうな箇所 ・壊れた結果が致命的な箇所 だけやればいいよね 一時期は、カバレッジ100%宗教に取り憑かれそうになったこともあったけどさ 単体テストを実装しても良いのなら喜んでそうするし、 工数の許す限り徹底的に作りこんで見せよう しかし実際の単体テストにおいては画面を決められた手順で操作して、 その結果のスクリーンショットを取ってエビデンスとしてまとめなければならない これを作りながらテストコードを実装するのは至難だ 後者をなくしてくれ、話はそれからだ スクリーンショットならテスト実行中に 自動的にキャプチャできるじゃんw >>202 何か勘違いしてる このスレでの「単体テスト(ユニットテスト)」に画面は必要ない >>204 画面キャプチャも取れないとか、んなハナクソ以下のテストしてやった気になってんじゃねーよ。 お前何年PGやってんだよ。センスないから辞めた方がいいよ。 社名 労基 でググると過去の2chスレが出てくる会社 and(orではない) 転職会議で2.5点の会社は超絶要注意 and 年齢不問IT系 転職の際はご注意ください >>202 ActiveAccesibilityで自動ボタン押ししてスクショとってExcelに貼るという 実にクソつまらんコードを書いたことはある。 WebだとWatir使ってる。 >>200 プログラマは 0-1 で割り切れないとやりたがらないからな。。 逆にいい感じにテスト書こうとすると ・難しい箇所 ・壊れやすそうな箇所 ・壊れた結果が致命的な箇所 の箇所がわかったり、局所化できたりするもんだね。 プログラマ志望なのに、主導テスト専門でやらされて、バグ修正してもらった結果、大幅にロジックが変えられていて、大幅にデグレしてまた主導テストやらされる。 こんな屈辱ない。 単体テストで画面がどうとかほざいてる馬鹿が多いんだよなぁ このスレにすら多い ホワイトボックステストでぐぐってから首吊って来いとしか言いようがないわ >>1 最初はテストデータの名前を適当にやっていたら何がどのテストデータ なのか分からなくなってしまい、名前を直し分かり易いように整理する のに物凄く時間がかかった事があるw このスレは初心者ばかりだな。 しかもテストフレームワークを使うことがテストみたいなことばかり言ってるし。 元ソースを全くいじらないでUTを実施する方法ってある? C++で 最初からどっかでDIできるようにちゃんと考えて設計してないと無理 >>217 dependency injectionていうんだ。知らなかった。ありがとう。 これ全く考慮されてないな。 ■ このスレッドは過去ログ倉庫に格納されています
read.cgi ver 07.5.0 2024/04/24 Walang Kapalit ★ | Donguri System Team 5ちゃんねる