単体テストでファイルの内容/エンコードをチェックすることは「悪い習慣」と見なされますか?


84

少しのコンテキスト:今日、私は別の同僚が提供したいくつかのSQLコードを更新する必要がありました。それは非常に大きなスクリプトであるため、別個のファイルとして保存されます(その後、実行時に読み取られて実行されます)。これを行っている間に、数か月前にあった2つのバグを誤って再導入しました。

  • 何らかの理由でASCIIファイルがUTF-16でエンコードされていました(同僚がファイルを電子メールで送信したため、ファイルが作成された可能性があります)。
  • スクリプトには初期SETステートメントがありませんでした(プロダクションでは一部のドライバーが必要ですが、ローカルでのクリーンインストールでは必要ありません)。

これを約1時間(再び)デバッグした後、これが二度と起こらないことを保証するためにいくつかの単体テストを書くことにしました(そして、将来の開発者に簡単な修正を提供するためにアサーションメッセージに修正する簡単な方法を含めます)。

しかし、このコードをプッシュしたとき、別の同僚(チームリーダーでもある)が近づいてきて、これらのことを二度とするべきではないと言った。

「これらのことは単体テストに属していません」

「ユニットテストは、コードのフローを確認するためにのみ使用してください」

このバグは将来再導入されないので、今やっていることは間違っていないと思うので、今はかなり対立していますが、この同僚は先輩として働いて、結局は何を決めるのですか?私たちは時間を費やしています。私は何をすべきか?このようにするのは間違っていますか?それは悪い習慣と考えられていますか?



35
ユニットテストは、コードのフローを確認するためにのみ使用する必要があります。」それはでたらめだと思います。伝統的に、それらは、単独で考慮される「ユニット」が正しいことを保証するために必要なすべてのテストを含むべきです。「フローをチェックする」のに役立つ単体テストのみを書く場合、それが何であれ、別の広範なテストスイート(QA部門によって作成された?)があることを願っています。
-gbr

8
とにかくあなたの同僚の問題は、おそらくあなたがそれらのテストを置く場所です。私はそれに焦点を合わせ、宗派の議論/聖戦はさておきます。これらのテストは追加したスイートには遅すぎる可能性がありますが、同僚が単体テストのアイデアに固執し、存在しない問題から問題を引き起こしている可能性もあります。そのため、まず実際の問題が何であるかを明確にすることをお勧めします。
-gbr

2
ところで、これらのテストは、そのSQLファイルを変更するたびに実行したいもののように見えます。ここでの主な問題は、テストツールである可能性があります。テストツールは、「変更された場合のみ実行」操作モードをサポートしない可能性があります。実際の具体的な問題が発生するため、これらの特定のテストのためだけに「修正された場合のみ」の機能を手作業で組み込むことは価値があります。
-gbr

5
ファイルが正しいコンテンツとエンコーディングを持っていることをテストする代わりに、それが機能することをテストしませんか?
user253751

回答:


156

ほとんどの場合、作成したテストは、単体テストよりも統合テストまたは回帰テストに近いものです。行は非常に曖昧である場合があり、場合によってはユニットテストであるかそうでないかを詳しく説明しますが、同僚に戻って、コードの正確性を保証する価値を追加するため、書いたテストの場所を尋ねます。

単体テストとは何かにあまり焦点を当てず、統合テストであってもテストに価値があることを認識しています。


コメントは詳細なディスカッション用ではありません。この会話はチャットに移動さました
トーマスオーエンズ

36

技術的には、単体テストではなく、検証ステップの詳細です。適切なアプローチは、ワークフローが必要なものに本当に依存します。チームリーダーは、単体テストの目的について正しいです。私の考えでは、これはまだ実行する必要があるジョブに間違ったツールを使用している場合です。だからこれから始めましょう:

私が解決しようとしている問題は何ですか?

説明により、データベーススクリプトがいくつかの標準に準拠していることを検証する必要があります。

問題を解決するために利用できるツール/プロセスは何ですか?

ソースコードの品質は通常、静的分析ツールによってチェックされます。SQLを検証する静的分析ツールがない場合は、渡されたSQLファイルのチェックを実行する迅速でダーティなツールを作成できます。あなたが話している問題を処理できる静的解析ツールがあるかどうかをチェックすることは害になりません。

Jenkinsなどに組み込むなど、ビルドインフラストラクチャの一部を作成すると、プロジェクト内のすべてのSQLファイルに適用できます。

単体テストは、現在のファイルの問題のみを解決します。

ツールの必要性をどのように伝えますか?

これは非常に簡単です。チームリーダーに相談してください。彼は製品所有者およびあなたと協力して、ツーリングへの投資のリスク/報酬を決定できます。これが1回限りの問題である可能性が高い場合、ツールは多すぎるでしょう。最大の問題をキャッチするためのツールが簡単な場合、健全性チェックのためだけに価値があるかもしれません。

チームリーダーは、あなた(または私)が考慮していないアイデアをいくつか持っている可能性があり、それにより問題をより正確に解決できます。


21
コストとリスクを議論するとき、以前に解決されたバグを再導入するためにすでに時間の損失を引き起こしていることに注意することが重要です。これだけでも、検証を自動化する強力な議論です。+1
jpmc26

1
@ jpmc26、私は完全に同意します。議論は、何が間違っているのかを理解するのに何時間も失ったという事実から始めるべきであり、ユニットテストはチームの残りが同じ時間を失うことを防ぐための最初の試みでした。ただし、経営陣や利害関係者に回答する必要があるチームリーダーと協力することは、通常非常に高く評価されています。チームリーダーとして、私たちが管理するツール/プラクティス/コードを防御できるようにしたいと考えています。実際の要件にたどり着けない単体テストを見た場合も、心配するでしょう。
ベリンロリチュ

1
@BerinLoritsch 技術的には、このアサーションのベースとなる「テクニック」について知りたい単体テストではありません。私が知る限り、単体テストの単一の正式な定義はなく、誰もが「彼らが」であるという独自の考えを持つようになりました。
-gbr

2
@gbr開発者の間で、ユニットテストは外部システムから分離して実行されるテストであるという非公式の合意があります。ファイル、データベース、またはその他の外部サービスとの相互作用ではなく、コード自体のみをテストします。:ウィキペディアはこのような理解文書化しen.wikipedia.org/wiki/Unit_testing#External_workを
jpmc26

1
@BerinLoritsch質問を別の方法で解釈している可能性もあります。とにかく、それはあまり詳細ではなく、作者はまだ誰にも返事をしていません。とにかくこれらのテストの分類についてさらに議論することにはあまり興味がありません、重要なのはそれらが存在するかどうか(私はかなりそうだと確信しています)と実行する頻度(IDEのすべての変更で、ローカルコミット、中央リポジトリへのすべてのプッシュ、毎回...)。
-gbr

19

ファイルにアクセスするテストを「単体テスト」と呼ぶのは悪い習慣です。

彼:「これらのことは単体テストに属していません」

あなた:「理にかなっていますが、私はそれらを置くよりよい場所を見つけることができませんでした。それらはどこに属しますか?」

残念ながら、どのような種類のテストが存在し、どのように構成されているかは、完全に企業固有です。そのため、会社がこれらのテストをどのように処理するかを知る必要があります。

ユニットテスト以外の自動テストを実行する方法がまだない場合、実用的なアプローチは、実際にユニットテストではないユニットテストに、どのような種類を把握できるようになるまでプレフィックスを付けることです。実際に持っている/必要なテスト。その後、整理を開始できます。


2
ファイルにアクセスするテストを「単体テスト」と呼ぶのは悪い習慣です。ここで、アクセスされているファイルはソースファイルです。(解析するために)ソースファイルと同じくらいアクセスされます。テストはおそらくチェック対象の「ユニット」と同じ言語(SQL)で行われないため、非正統的ですが、ユニットテストとしての分類に影響を与えるべきではありません。続く
...-gbr

1
...実際には、ファイルの正しいエンコーディングは、ソースファイルを読み込むたびにコンパイラによって作成される「テスト」です。ここでの問題は、実行時に解釈される外部ファイルであるため、「コンパイラテスト」が自動的に実行されないため、明示的に追加することが完全に適切であり、その「ユニットテスト」 SQLスニペット。また、ファイルを変更するたびに実行される(潜在的な)テストスイートに含めることは理にかなっています。
-gbr

3
ところで、一般的に推奨されるのは、外部ファイルにアクセスすることです。これは、モックまたはそれに沿った何かで置き換えることができます。また、ほとんどの定義では、単体テスト外部ファイルなどにアクセスできますが、物事が大幅に遅くなる可能性があるため、強くお勧めします。ショップは、最も頻繁に実行されるテストスイートにファイルにアクセスするテストを追加することはできませんが、そのようなテストを「単体テスト」の指定にふさわしくなく、単にこのプロジェクトの最も頻繁に実行されるテストのスイートに入れられる」。
-gbr

2
@Warbo である(一般的に)ファイルにアクセスするには、悪い習慣、および(最も重要な)理由は、彼らが「GB単位は、フレーク状NFSリンクを介して読んで」伴う場合例えばマイケル羽を引用し、場合、彼らは遅い遅いされていないということです、1/10秒かかります。これは、できるだけ頻繁に、理想的にはIDEで行ったすべての変更で、テストをできるだけ頻繁に実行したいためです。(続き...)
gbr

1
@Warbo ..とはいえ、重要なのはそれらにかかる合計時間であるため、非常に小規模なプロジェクトであっても確実に小規模にとどまる場合は、個々のテストの速度についてもっと寛大になります。頻繁に実行する必要がない場合は、OPMROCの従業員に電話してキャビネットからファイルを取得してFAXで送信することもできます。また、まだテストがほとんどない間に、より緩いものを選択し、テストに時間がかかりすぎる場合はテストを高速化することもできますが、これは蓄積している負債であることを考慮する必要があります。
-gbr

14

マイケルフェザーズは、彼の著書「レガシーコードを効果的に使用する」で次のように述べています。

業界では、特定のテストが単体テストであるかどうかについて頻繁に行き交います。[...] 2つの特性に戻ります。テストは高速に実行されますか?エラーをすばやく特定できますか?

テストはエラーの迅速なローカライズと高速実行に役立ちますか?はいの場合、それを行います!いいえの場合は、しないでください!それはそれと同じくらい簡単です!

そうは言っても、あなたは他の人々と一緒に環境で働いており、彼らと仲良くしなければなりません。あなたが個人的にそれに反対したとしても、あなたはそれを彼のやり方でやらなければならないかもしれません。


それは良い経験則ですが、「ユニットテスト」という用語をいじるのではなく、「最も頻繁に実行されるテストスイートに特定のテストを追加するかどうか」を書いていれば混乱を免れたでしょう。
-gbr

1
@gbrテストの結果が正確であれば、他に重要なことは、テストの実行速度です。それぞれが0.1秒未満で実行されるテストが100個ある場合、合計で10秒未満で実行されます。それらを頻繁に実行できてうれしいです。1000個のテストがある場合、最大1分40秒かかります。それは長すぎるので、頻繁に実行することはありませんが、100個のテストの小さなグループで変更を加えたら実行します。技術的に受け入れテストなのか、他の何かなのかは気にしません。エラーをより早く見つけるのに役立つ場合は、セマンティクスに関係なくそれを行います。テストは、実行時にのみ価値を提供します。
CJデニス

私はほとんど同意します(例えば、独立性は別の非常に重要なことです)が、それでもマイケル・フェザーズが「ユニットテスト」の意味についての混乱を悪化させなかったらもっと良かったでしょう。彼がその混乱を特に責めているわけではありません(そして彼の本は、これまで私がざっと目を通した部分で素晴らしいです)。とにかく、私はかなりマイナーなポイントを挙げていました。
-gbr

@gbr彼は単体テストを再定義しているのではなく、それを含めるべきではないということを言っています。あなたの基準は有用であるべきであり、それが彼が定義していることです。
CJデニス

そのセクションを読み直しました。わからない、それが(ある種の)定義なのか、単なる基準なのかわからない。しかし実際には、「エラーを迅速にローカライズするのに役立ちますか」は、以前に彼が言ったこと、隔離についてなどを非常によく暗示しているかもしれません。だから私は(単独で、あなたの答えはまだ誤って解釈される可能性があるが)何についての大騒ぎをしたかもしれない
GBR

10

ソースコードファイル、構成ファイルなどに対して、ときどき同様のテストを作成しました。(a)ファイルシステムにアクセスしており、超高速ではない可能性があるため、ユニットテストとは呼びません(b)チェックインごとに実行されるかどうかは気にしません(夜間ではなくCIサーバー)。

それらを統合テストと呼ぶかもしれません。確かに、彼らはユニットテストよりもその観点に近い。

それらの私自身の用語はリソーステストです。私見、CIサーバーで毎晩実行される場合、これらは完全に正当化されます:最小限のコストがあり、賢明に使用された場合、明らかに付加価値があります。賢明な定義:テストが問題を引き起こした問題をチェックしている場合(あなたが言及したエンコーディングなど)。


4

単体テストは、メソッドまたはコードの「ユニット」のテストに関するものです。ソフトウェアのロジックとコードの最小グループをテストしています。

後で、それを他のユニットと結合すると、統合テストが実行されます。

あなたのチームリーダーがあなたのイニシアチブを奨励し、別の提案を提供するべきだったと思います。あなたは間違いなく正しい考えを持っています。

SQLは、C#やJavaなどの低世代言語とまったく同じコードであるため、そのようにテストする必要があります。そして、検証と検証はすべてのテストレベルに属します。そのため、エンコードとSETステートメントが含まれますが、必ずしも排他的にテストされるわけではありません。行末や囲みなどの一般的なものは、通常、SCMフックまたは機能を使用するだけです。

ベストプラクティスは、過去のバグが再導入されないようにするための回帰テストを実施することです。一般的に、テストはバグの解決とともに作成されます。これらのバグがユニット/統合またはシステムレベルでのリグレッションテストでカバーされず、再導入された場合は、個々の問題ではなく、チームの問題であり、プロセスの問題です。

問題は...構文エラー、欠落したステートメント、または「ユニット」内の論理ブロックは通常テストされません。ユニットの入力と出力をさまざまな組み合わせでテストし、生成される可能性のある多くの可能性をテストしています。

欠落しているSETステートメントに戻る-テストする入力と出力の多くの可能性を知らせるのに役立ちます。選択したSETが欠落している場合、失敗するテストはどのようなものですか?


「コードの単位」テストは、単体テストへの1つのアプローチです。私の経験では、これは脆弱なテストと巨大な膨張(例:過度のモッキング)につながります。単体テストに対する代替の、そしてより良いアプローチは、「機能のユニット」です。一部の機能(「ログイン時にCookieを設定する」など)が1つのメソッドまたは1ダースの相互通信プロセスを必要とする場合でも、それは1つのユニットです。
ワーボ

@Warbo-統合テストに近い(しかしそうではない)と呼びます。単体テストでは、過度のまたは大規模なものは必要ありません。単体テストは小さくて高速でなければなりません。実際には、機能によるテストは、あなたが説明するものにつながります。壊れやすいテストとは、1。規模が大きいか、必要以上のことを行うものです。2.高度に結合3.単一の責任を負わない。
ロス

3

製品の一部となるファイルがある場合、その内容は正しいものでなければなりません。これを検証しない理由はありません。たとえば、あるフォルダに6つの1024x 1024の画像が必要な場合は、必ずそれを確認する単体テストを作成してください。

しかし、おそらくファイルだけではなく、ファイルを読み取るコードもあります。そのコードの単体テストを書くことができます。上記の例では、6つのイメージの1つを読み取る関数は、メモリ内の1024 x 1024イメージ(または生成されるはずのイメージ)を返します。

とにかく、単体テストではないかもしれませんが、有用なテストです。また、有用なテスト(単体テストではない)を実行できる単体テストフレームワークを使用している場合、単体テストフレームワークを使用してみませんか?


2

おそらく私はあなたの問題を誤解しているかもしれませんが、私にはこれは何らかの種類の専用のテストではなく、単にバージョン管理システムによって捕捉される必要がある問題のように聞こえます。コードベースへの変更は、コミットする前にパッチごとにレビューする必要があります。gitでこれを行う簡単な方法は、変更を追加することです

git add -p

これにより、テキストファイルの変更ごとに、作業ディレクトリが本当にそれを保持するかどうかを尋ねます。これにより、たとえば、これらの「初期SETステートメント」の削除を確認できます。

ただし、ファイル全体のエンコーディングが変更された場合、異なるものが発生します。アルゴリズムは、古いファイルと新しいファイルを比較できgit add -pないため、何も追加しません。これは、コミットする前に行う他のコマンド、つまり、

git status

ここでは、そこにあることを示し、赤でハイライトされたファイルを参照してくださいねある変化。これらがうまくいかなかった理由を調査git add -pすることで、問題がすぐに明らかになります。


祈って、これは将来の開発者がまったく同じ問題を回避するのにどのように役立ちますか?...自動化されたテスト(アサーションおよび契約ごとの設計についても有効)に関することは、それらがまあ、自動化されているということです。
vaxquis

@vaxquisは、まったく同じ問題を防ぎます-多少の偶然ではありますが、ワークフローの副作用として、さまざまな理由で良い考えです。私のポイントは、この問題は、OPのチームがVCSをあまり活用していないことを示しているということです。—自動化されたテストに対しては何もありませんが、それらの価値は、プログラムロジックへの無害な変更によって破壊される可能性があるセマンティックプロパティをテストすることです。ソースコードが変更される可能性のあるすべての愚かな方法をチェックすることではありません。
leftaroundabout

あなたの論理では、シートベルトは必要ありません。私たちはもっと慎重に運転し、事故を少なくする必要があります... OPが提起した主要なポイントを見逃しました-それはヒューマンエラーです。それからあなたを守ることができるVCSの量はありません。また、FWIW:テストを自動化できる場合は、自動化する必要があります。人間は常にエンジニアリングプロセスで最も弱いリンクです。gitそれはその最高の例です-素晴らしいツールでありながら、単なる人間にとってはほとんど使用できません。
vaxquis

@vaxquisいいえ、いいえ!シートベルトは、理にかなっている種類のテストに似ています:偶然に発生する可能性のあるさまざまな状況をキャッチします。ファイルエンコーディングのテストは、ロボットを追跡し、鼻に豆を詰め込んで窒息するのを防ぐロボットに似ています。
leftaroundabout

OPによると、間違った形式のファイルはすでに2回発生しているため、偶然に発生する可能性高いようです。
-gnasher729

1

考慮すべき別の角度:これらの2つの条件は、プログラムを実行するための要件であるため、実行ロジックの近くにロジックを埋め込むべきではありませんか?つまり、ファイルを読み取る前にファイルの存在をテストしたり、コンテンツを検証したりします。これはどう違うの?これはコード外部リソースであるため、実際に使用する前に、実行時に検証する必要があると思います。結果:より強力なアプリ、追加のテストを記述する必要はありません。


1
実行時にのみ失敗すると、どのように強力なアプリになりますか?もちろん、ランタイムチェックを問題の原因に近づけることも適切かもしれませんが、ランタイムの問題を引き起こすにミスを検出できれば、はるかに優れていると思いませんか?自動テストに慣れていますか?
-gbr

1
「実行時にのみ失敗すると、より強力なアプリになりますか?」チェックが失敗した場合、例外をスローします。テストでは、テスト対象のコードのセクションが期待される結果を返すことを確認します。これにより、失敗のもう1つの理由を確認する負担がなくなります。
ジャンルイジゼーンザネッティニ博士

1
あなたの戦略は、(ほとんど)単体テストや自動化されたテストとは何の関係もありません。それは異なるものであり、用途も異なります。
-gbr

1
これを提案するつもりでした。バグは実装の詳細です。危険なエンコーディングがスタンドアロンファイルではなくプライベートフィールドにある場合、応答は非常に異なると思います!OPには2つの問題があるようです。リソースファイルのエンコードが不適切である可能性があり、プロダクションの動作がdevとは異なります。使用する直前に実行時にファイルをチェックすることで、2番目の問題を解決します。devとprodは同じエラーをスローします。単体テストでは、実装の詳細ではなく、実際の機能に焦点を当てることができます。これらの「内部」チェックは、プライベートメソッドと同様に実行されます。
ウォーボ

1
@ Dr.GianluigiZaneZanettini Bah ...私はあきらめます...私が見るように、あなたの答えは、せいぜい、コメントでの「説明」の後、トピックから外れていました(質問に対する答えではありません)が、実際には、現状では、明らかに間違っています!追加のテストを書く必要はありません ??? 私はそれを支持するのに十分な評判がありませんが、あたかもそれをしたかのように考えてください。そして、この会話を続けることにはあまり価値がないと思います。
-gbr

1

テストは他のテストと同じコードであり、十分に複雑な場合は、ユニットテストの恩恵も受けます。このような前提条件チェックをテストに直接追加するのが最も簡単なようです。

ほとんどのテストはこれを必要としないほど単純ですが、一部が十分に複雑な場合、これらの前提条件チェックに根本的な問題は見られません。もちろん、それらがなければテストも失敗するはずですが、適切な単体テストはどのユニットが失敗しているかを示します。

テストの一部として使用され、特定のコンテンツとエンコードが必要なスクリプトは、おそらくユニットです。他のテストよりもはるかに多くのコードとロジックが含まれている場合があります。このようなスクリプトを使用したテストは、これまでで最高の設計ではないため、可能であれば、より直接的なものにリファクタリングする必要があります(統合テストでない限り)。


1
著者は、そのSQLスクリプトが何らかのテストの一部であることをどこにも言っていないので、質問を誤解しているようです
-gbr

理解が難しいので、SQLスクリプトはテストの一部であると思います。
h22

あなたのコメント「わかりにくい」
...-gbr

理解しにくいです。質問に投票する。
h22

1

まず、テストの目的の1つは、コード内での問題の再発を防ぐことです。したがって、この種のテストを作成し続ける必要があります。

第二に、命名は難しい。はい、これらは明らかに「ユニットテスト」ではありませんが、明らかな間違いからあなたを守り、エラーについてのフィードバックをより早く提供するため(特に、開発ボックスの結果)。

ですから、実際の問題は、実際の状況よりも、これらのテストをいつ、どのように実行するかということです(あなたのコンテキストにあるべきです)。

私は過去にこの種のテストを広範囲に使用しました-それらは私たちにかなりの痛みを軽減しました。


そして、誰かがダウン票を説明したいと思うなら、感謝します
マーフ

1

ユニットテストは、コードのユニットを単独で実行して、正しい入力に対して正しい結果を生成していることを確認することです。分離は、テスト対象のユニットとテスト自体の両方を再現可能にする必要があります。つまり、副作用に依存したり、副作用を導入したりしないでください。

SQLは単独でテストできるものではないため、SQLのテストはユニットテストではないため、SELECTステートメントを除いて、副作用があることはほぼ確実です。単体テストではなく、統合テストと呼ぶことができます。

導入される可能性のある欠陥を開発サイクルのできるだけ早い段階で検出できるようにすることは常に賢明であり、迅速に検出できるように欠陥の原因を簡単に特定できるようにすることは有益です修正しました。

問題のテストは、「ユニットテスト」の本体からより適切に再配置され、別の場所に配置される可能性がありますが、追跡に数時間かかる可能性のある欠陥の導入を防ぐなどの有用なことを行っている場合は、完全に削除しないでくださいダウン。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.