レガシーコード(わかりません)の単体テストを作成するにはどうすればよいですか?


8

進む

この質問をする前に、SEに関する多くの関連する質問を含め、多くのことを読みました。

しかし、助けを求めて読んだ後、かゆみはまだ引っかかれていないと感じざるを得ません。


TL; DR

実行、シミュレーション、読み取り、または簡単に理解できないレガシーコードの単体テストを作成するにはどうすればよいですか?おそらく意図したとおりに機能するコンポーネントに役立つ回帰テストは何ですか?


全体像

私は大学院に移行しているので、再び夏の帰国研修生です。私の仕事には次の要件が含まれます。

  1. 特定の製品について、ソフトウェアチームが既存のプロジェクトとの互換性を失うことなくIDEおよびJUnitバージョンをアップグレードできるかどうかを評価します。
  2. 既存のJavaコード(主にJavaではない)の一部のコンポーネントの単体テストを開発します。ユニットテストとTDDは、使用する必要がある非常に貴重なツールであることをソフトウェアチームに納得させたいと思います。(現在、0%のコードカバレッジがあります。)
  3. どういうわけか、重要なシステムのカウボーイコーディングの時代を終わらせてください。

ソースコードのコピーを入手した後、この製品の機能と動作を理解できるように、ビルドして実行しようとしました。できませんでした。私は上司に自分のやり方を尋ね、実際に機能するビルドスクリプトを含む、それをビルドできる新しいスタンドアロンマシンを発行されました。彼らの予想通り、製品コードは設計された組み込みシステムでのみ実行されるため、それも機能しませんでした。しかし、彼らはこの目的のためにシミュレーターを持っているので、彼らはシミュレーターを手に入れ、このマシンにそれを置いてくれました。シミュレータも機能しませんでした。代わりに、私は最終的に特定の画面のGUIのプリントアウトを受け取りました。また、700,000以上のJava LOC内のどこにもコードコメントがないため、把握がさらに困難になります。さらに、彼らのプロジェクトが新しいIDEと互換性があるかどうかを評価する問題がありました。特に、彼らのコードは、彼らが使用しているまさにそのIDEバージョンに適切にロードされませんでした。

私の在庫は次のようになっています:

  • NetBeans 8、9、10、11
  • JUnit 4、5
  • 特定の製品のソースコード(700,000以上のJava LOCを含む)
  • 実質的にコードコメントはありません(場合によっては署名)
  • 既存のテストはありません
  • GUIウィンドウの物理的な写真
  • 画像内のコンポーネントについて説明していないソフトウェア設計ドキュメント(109ページ)

少なくとも理論的には実行可能なテストを書くのに十分です。そこで、このコンポーネントについて基本的な単体テストを試しました。しかし、モデル、マネージャー、DB接続など、依存関係として持つオブジェクトを初期化できませんでした。基本的な単体テスト以外にJUnitの経験はあまりないので、次のセクションに進んでください。


私の読書から学んだこと

  1. モッキング:単体テストを作成する場合、本番環境での依存関係のために、モック変数を用意する必要がありますsetUp
  2. ここの誰もがマイケルフェザーズの著書「レガシーコードを効果的に使用する」を寛大に提案しています。
  3. 回帰テストは、おそらく開始するのに適しています。統合テストを試すのに十分な兵器がないと思います。回帰テストは、ソフトウェアチームにすぐに満足感を与えるでしょう。ただし、私は彼らの既知のバグにアクセスできません。しかし、私はたぶん尋ねることができました。

そして今、私がまだ疑問として持っている不確実性を明確にする試み。基本的に、私はこれらのテストを作成する方法の一部を理解していません。(おそらく)上司からこれ以上のガイダンスを受け取らないと想定すると、このコンポーネントの機能を理解するだけでなく、どのテストが回帰テストとして実際に役立つかを判断するのは私の球場です。

このようなプロジェクトに携わってきた専門家として、このような状況で単体テストを作成する方法について何かアドバイスはありますか?


12
How do I write unit tests for legacy code that I can't build, run, simulate, read about, or otherwise understand?-できません。少なくとも、特定の入力に対して期待される出力が何であるかを知っている必要があります。
Robert Harvey

1
マイケルフェザーズの本をもう読みましたか。
ロバートハーベイ

@RobertHarveyそれはわずかな誇張です。時間をかけてコードを読んで理解できることは明らかですが、これは通常、非常に大きなものを使用する最後の手段です。いえ、今朝まだ本を見つけたばかりなので、まだです。
ジョシュアDetwiler

ビルドすることさえできないレガシーコードがある場合、正しいバージョンのコードさえあると確信していますか?自動テストについて心配する前に、まずこれを解決する必要があります-作成しようとしているコードは、ユーザーが実行しているものと同じですか?実行中のシステムが稼働している場合の最初のステップは、ユーザーの視点からシステムを理解しようとすることです。ユーザードキュメントを読んだり、可能であればユーザーデータを調べて、その内容を理解したりするのに役立ちます
Ben Cottrell

2
センサーデータが実行に不可欠である場合、センサー(または外部の依存関係が何であれ)をモックすることから始めるのが良いようです。
JimmyJames

回答:


10

第一に、テストスイートの関係者は、コードの開発者/保守者です。あなたは彼らの時間のいくらかを必要とするでしょう。これを主張する。

彼らが直面している問題について彼らに尋ねます。
彼らが最近修正したバグについて質問します(過去数年で、これは非常に時間がかかるプロジェクトだと想定しています)。

あなたは彼らがあなたの仕事に親しみやすいと期待していないような印象を受けます。多分あなたは正しいです。しかし、私はあなたが彼らの助けなしに有用なものを構築できるとは思いません。

彼らは最初のテストを書くまであなたの手を握ります。多分あなたはそれらをドラッグするでしょうが、あなたはどちらかの方法で手をつなぐでしょう。

1つのテストを作成したら、2番目の記述方法が明確になることを願っています。あなたが何らかの関係を築くことができたなら、それは確かにより明確になります。


答えてくれてありがとう!私の質問の後半も見ていただけますか?私の前半は、リンクした質問を少し複製することでした。そのため、私の質問の他の部分に主に興味を持っていました。
Joshua Detwiler

どれほど役に立てるかわからない。テストフレームワークの仕組みを理解するのに苦労していませんか?をテストしたらいいの気になりますか?そのため、回帰テストは良い選択ですもし私たちが非常に洞察力があったとしたら、どのテストがこのバグがプッシュされるのを防ぐことができたでしょう
ShapeOfMatter

それは、「意図したとおりに機能すると思われるコンポーネントにとって、どの回帰テストが役立つのか」ということでした。たとえば、有用なテストを作成する場合、何が機能し、何が機能しないか、まったく機能しないことを完全に盲目にすると、何が役立つのでしょうか。私はソフトウェアチームとは別に孤立していて、私にこの仕事をしてくれた人たちは私たち2人とは別に孤立しています。
Joshua Detwiler

あなたがソフトウェアを書いている人々と同じ部屋に入ることを主張する必要があると私はまだ確信しています、理想的には数日間、そしておそらく2回以上。私は課された不条理な労働状況に関係することができますが、ある時点で、人は仕事を危険にさらすか、あなたが単なるベンチウォーマーであることを受け入れる必要があると思います
ShapeOfMatter

回帰テストについて:他のテストと概念的に違いはありません:プログラムが機能していることを同僚に要求する前に、プログラムに何を実行(または実行しない)したいですか?新機能や最近のバグの記録がある場合は、それらを開始するのに適しています。または、手元にあるドキュメントを調べて、テスト可能と思われるものを選択してください。Javaには型付きの関数があり、これは良いことです。明確な型シグネチャは、関数から何を期待するかについて多くを伝えることができます(そしてそれ自体が一種の単体テストと考えることができます)。NULL /空の文字列/最大整数の動作をチェックすることも良いでしょう。
ShapeOfMatter

3

いつかは、コードを少なくともコンパイルできると仮定します。そこまでたどり着けないなら、あなたは愚か者の用事にいる。


適切な要件、仕様、またはスクリーンショットがないことは、テストを作成する上での障害にはなりません。ソースコードを読むことができる限り、テストを書くことができます。

独自のインターフェースの背後にあるデータベース接続などを分離するためにコードベースをリファクタリングする権限が与えられている場合、いくつかのブラックボックスユニットテストを作成することが可能になります。1つの方法でコードの各行をカバーするテストを取得し、チームの上級メンバーの1人にテストをレビューしてもらいます。

ユニットテストを作成するためにコードベースをリファクタリングする権限が与えられていない場合は、完全な統合テストまたはUI自動化テストが唯一の選択肢です。それでも、ブラックボックステストが最善の戦略です。UIにいくつかの入力を投げて、それがどのように反応するかを確認します。あなたの主張をしてください。チームの上級メンバーにテストをレビューしてもらいます。

ある時点で、ユニットテストを導入するための自信を持ってコードベースのリファクタリングを開始できる十分な自動テストが作成されます。UIテストでは、主要なビジネスユースケースが機能することを確認してから、ユニットまたはコンポーネントレベルのテストに役立つアーキテクチャを後付けできます。

UIテストのもう1つの利点は、コードベースを理解しているチームとの評判を築くことができるということです。これは、証拠がプディングにあるため、変更を導入することに対してオープンになります。そして、あなたは合格したテストを書くことによってプリンを作ったでしょう。

要するに:

  • ブラックボックステストを単体テストまたは自動UIテストとして作成する
  • 上級メンバーにテストをレビューしてもらいます

700,000行のアプリケーションの全体像をどれだけすばやく学習できるかは驚くでしょう


1

問題の説明とコメントに基づいて、できる最善の方法は、Java APIから始めて、分離されたメソッドの周りに単一の単体テストを構築することです。

コードにアクセスできないと、限られたガイダンスしか提供できませんが、a)依存関係がないb)状態が変化しないものを探します。例えば。値を受け取り、それが指定された範囲内にあることを確認するメソッドがあるとします。依存関係のないものが見つからない場合は、依存関係から値を取得するものを試し、それを模擬してみてください。

このような小さなものが見つかったら、テストの作成を開始できます。メソッドが正の値をテストする場合は、負の値を渡して、それがキャッチされることを確認します。ここでの問題は、正しい動作が何かがわからない場合があることです。あなたは助けを求めるか、そのためのドキュメントを掘り下げる必要があるかもしれません。

あなたはこれで非常に遠くに行くことはほとんどありません。現実には、ユニットテストが可能なようにコードを書くこと自体が芸術です。これを念頭に置いて作成されていないコードは、単体テストが不可能になる可能性があります。

より簡単に実装できるもう1つのオプションは、バイナリ互換性テストです。つまり、システムの入力と出力をキャプチャしてから、テストするためにそれらの同じ入力をフィードして、出力を比較します。これは、コードが最初から正しいか間違っているかを教えてくれませんが、他の変更を行ったときに意図せず変更された回帰エラーを検出するのに役立ちます。ただし、それを実現するには、アプリケーション全体を実行できる必要があります。

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