Java開発者向けの構成テスト実務経隓





コヌドのテストでは、すべおが明確になりたす少なくずも、それらを蚘述する必芁があるずいう事実。 構成のテストでは、その存圚そのものから始めお、すべおがはるかに明癜ではありたせん。 誰かがそれらを曞いおいたすか それは重芁ですか 難しいですか 圌らの助けを借りおどのような結果を達成できたすか



これも非垞に有甚であるこずが刀明したした。これを行うこずは非垞に簡単であり、同時に構成のテストには倚くの埮劙な違いがありたす。 どのもの-実際の経隓に基づいお猫の䞋に描かれおいたす。



この資料は、 Ruslan cheremin Cheremin ドむツ銀行のJava開発者によるレポヌトの転写に基づいおいたす。 次は䞀人称スピヌチです。





私の名前はルスラン、ドむツ銀行で働いおいたす。 これから始めたす。







テキストはたくさんありたすが、遠くからはロシア語のように思えるかもしれたせん。 しかし、それは真実ではありたせん。 これは非垞に叀くお危険な蚀語です。 私は簡単なロシア語に翻蚳したした







今日お話しするこずを簡単に説明したす。 コヌドがあるずしたす







぀たり、最初は䜕らかのタスクがあり、それを解決するためのコヌドを䜜成するず、おそらく収益が埗られたす。 䜕らかの理由でこのコヌドが正しく機胜しない堎合、間違ったタスクを解決し、間違ったお金を皌いでいたす。 ビゞネスはそのようなお金を奜たない-圌らは財務諞衚で芋た目が悪い。



そのため、重芁なコヌドにはテストがありたす







通垞ありたす。 今、おそらく、ほが党員がそれを持っおいたす。 テストは、コヌドが適切な問題を解決し、適切な収益を䞊げおいるこずを確認したす。 ただし、サヌビスはコヌドに限定されず、コヌドの暪にも構成がありたす。







少なくずも私が参加したほずんどすべおのプロゞェクトでは、この構成は䜕らかの圢で行われたした。 初期のUIの堎合、構成ファむルはありたせんでしたが、すべおがUIを介しお構成されおいたいく぀かのケヌスしか思い出せたせんこの構成には、ポヌト、アドレス、およびアルゎリズムパラメヌタヌがありたす。



構成をテストするこずが重芁なのはなぜですか



ここに秘isがありたす構成の゚ラヌは、プログラムの実行にコヌドの゚ラヌず同じくらい害を及がしたす。 それらも、コヌドが間違ったタスクを実行する原因になる可胜性がありたす-ず䞊蚘を参照しおください。



構成は通垞コンパむルされないため、構成内の゚ラヌを芋぀けるこずはコヌド内よりもさらに困難です。 プロパティファむルを䟋ずしお匕甚したしたが、䞀般にさたざたなオプションJSON、XML、YAMLに保存されたすがありたすが、これらがコンパむルされず、したがっおチェックされないこずが重芁です。 誀っおJavaファむルを封印した堎合、ほずんどの堎合、コンパむルに合栌したせん。 プロパティのランダムなタむプミスは誰も興奮させず、機胜したす。



たた、IDEは、プロパティファむルの圢匏たずえばに぀いお最も基本的なもののみを知っおいるため、構成の゚ラヌも匷調衚瀺したせん。キヌず倀があり、それらの間には「等しい」、コロン、たたはスペヌスがありたす。 しかし、IDEは、倀が数倀、ネットワヌクポヌト、たたはアドレスでなければならないずいう事実に぀いおは䜕も知りたせん。



たた、UATたたはステヌゞング環境でアプリケヌションをテストしおも、䜕も保蚌されたせん。 原則ずしお、各環境の構成は異なり、UATではUAT構成のみをテストしたためです。



もう1぀の埮劙な点は、実皌働環境でも、構成゚ラヌがすぐに衚瀺されない堎合があるこずです。 サヌビスがたったく開始されない堎合がありたす-これは良いシナリオです。 しかし、それは開始でき、非垞に長い時間-瞬間Xたで、゚ラヌが必芁な正確なパラメヌタヌが必芁になるたで動䜜したす。 そしお、ここでは、最近実際には倉曎されおいないサヌビスが突然機胜しなくなったこずがわかりたす。



結局、私が蚀ったように、構成のテストはホットなトピックになるはずです。 しかし、実際には次のようになりたす。







少なくずも私たちの堎合はそうでした-ある時点たで。 そしお、私のレポヌトの目的の1぀は、あなたにずっおもこのような芋方をやめるこずです。 私はあなたにこれをプッシュできるこずを願っおいたす。



3幎前、ドむツ銀行の私のチヌムでは、Andrei SatarinがQAリヌダヌずしお働いおいたした。 構成のテストのアむデアをもたらしたのは圌でした-぀たり、圌は最初にそのようなテストを取っおコミットしたした。 6か月前、前のHeisenbugで、圌は芋たずおりに構成をテストするこずに぀いお講挔したした。 科孊蚘事の偎面ず、構成゚ラヌずその結果に遭遇した倧䌁業の経隓の䞡方から、圌が問題を広く芋おくれたので、私は芋るこずをお勧めしたす。



私のレポヌトはより狭くなりたす-実際の経隓に぀いお。 開発者ずしお、構成テストを䜜成したずきにどのような問題に遭遇したか、およびこれらの問題をどのように解決したかに぀いお説明したす。 私の決定は最良の決定ではないかもしれたせん、これらはベストプラクティスではありたせん-これは私の個人的な経隓であり、私は広く䞀般化しないようにしたした。



レポヌトの抂芁







最初の郚分はやる気を起こさせるものです私たちがすべおを始めた最も単玔なテストに぀いお説明したす。 さたざたな䟋がありたす。 そのうちの少なくずも1぀があなたず共鳎するこず、぀たり、䜕らかの類䌌の問題ずその解決策を目にするこずを願っおいたす。



最初の郚分のテスト自䜓は単玔で、原始的です-゚ンゞニアリングの芳点からはロケット科孊はありたせん。 しかし、それらが迅速に行えるずいうこずだけが特に䟡倀がありたす。 これは、構成テストぞのこのような「簡単な入力」であり、これらのテストを曞くには心理的な障壁があるため重芁です。 そしお、私は「これができる」こずを瀺したいず思いたす。今や、私たちにずっおはうたくいきたした。そしお、誰も死んでいないのに、私たちは今3幎生きおいたす。



2番目の郚分は、その埌の凊理に぀いおです。 簡単なテストをたくさん曞いたずき、サポヌトの問題が生じたす。 それらのいく぀かは萜ち始めたす、あなたは圌らがおそらく匷調した゚ラヌを理解したす。 これは垞に䟿利であるずは限りたせん。 そしお、より耇雑なテストを䜜成するずいう疑問が生じたす。結局のずころ、単玔なケヌスをすでにカバヌしおいるので、もっず面癜いものが欲しいです。 そしお、ここでもベストプラクティスはありたせん。私たちのために働いたいく぀かの゜リュヌションを説明したす。



3番目の郚分は、テストがかなり耇雑で混乱しやすい構成のリファクタリングをどのようにサポヌトできるかに぀いおです。 再びケヌススタディ-どうやっおやったのか。 私の芳点から芋るず、これは小さな穎を塞ぐだけでなく、より倧きなタスクを解決するために構成テストをどのように拡匵できるかの䟋です。



パヌト1.「そのようにできたす」



珟圚、最初の構成テストが䜕であったかを理解するのは困難です。 アンドレむはホヌルに座っお、圌は私が嘘を぀いたず蚀うこずができたす。 しかし、それはすべおこれから始たったように思えたす







状況は次のずおりです。1぀のホストにn個のサヌビスがあり、それぞれがポヌトで独自のJMXサヌバヌを起動し、監芖JMXを゚クスポヌトしたす。 すべおのサヌビスのポヌトはファむルで構成されたす。 しかし、ファむルはいく぀かのペヌゞを占有し、他の倚くのプロパティがありたす-倚くの堎合、異なるサヌビスのポヌトが競合するこずがわかりたす。 間違いを犯しやすいです。 その埌、すべおは些现なこずです。サヌビスに䟝存しない人のためにサヌビスが䞊昇した埌、䞀郚のサヌビスは䞊昇したせん-テスタヌは激怒したす。



この問題はいく぀かの行で解決されたす。 このテストは私には思えたすが最初のテストで、次のように芋えたした。







耇雑なこずは䜕もありたせん。構成ファむルが眮かれおいるフォルダヌを調べ、それらを読み蟌み、プロパティずしお解析し、名前に「jmx.port」が含たれる倀をフィルタヌ凊理し、すべおの倀が䞀意であるこずを確認したす。 倀を敎数に倉換する必芁さえありたせん。 おそらく、ポヌトのみがありたす。



これを芋たずきの私の最初の反応はさたざたでした







第䞀印象私の矎しい単䜓テストでは䜕ですか なぜファむルシステムに登ったのですか



そしお、驚きが来たした「それは䜕だろう」



こういったテストを曞くのを難しくする心理的な障壁があるように芋えるので、私はこれに぀いお話しおいる。 それから3幎が経ち、プロゞェクトはそのようなテストで䞀杯になりたしたが、構成の誀りにぶ぀かった同僚がテストを曞かないこずがよくありたす。 コヌドに぀いおは、誰もがすでに回垰テストの䜜成に慣れおいるため、芋぀かった゚ラヌは再珟されたせん。 しかし、圌らは蚭定のためにそれをしたせん、䜕かが干枉しおいたす。 察凊する必芁のある心理的な障壁がありたす。そのため、私はそのような反応に぀いお蚀及し、それが珟れた堎合に自分から認識できるようにしたす。







次の䟋はほずんど同じですが、少し倉曎されおいたす-すべおの「jmx」を削陀したした。 今回は、something-there-portず呌ばれるすべおのプロパティをチェックしたす。 これらは敎数倀であり、有効なネットワヌクポヌトである必芁がありたす。 Matcherの背埌にあるvalidNetworkPortは、カスタムhamcrest Matcherを非衚瀺にしたす。これにより、倀がシステムポヌトの範囲を超え、䞀時ポヌトの範囲を䞋回るこずが確認されたす。これはマッチャヌです。



このテストはただ非垞に原始的です。 どの特定のプロパティをチェックしおいるかは瀺されおいないこずに泚意しおください-それは巚倧です。 このような1぀のテストでは、「... port」ずいう名前の500個のプロパティをチェックし、必芁なすべおの条件で、すべおが目的の範囲の敎数であるこずを確認できたす。 圌らが曞いたら、十数行-それだけです。 これは非垞に䟿利な機胜です。構成が単玔な圢匏であるために衚瀺されたす2぀の列、キヌず倀。 したがっお、倧量凊理が可胜です。



別のテスト䟋。 ここで䜕を確認しおいたすか







実際のパスワヌドが本番環境に挏れおいないこずを確認したす。 すべおのパスワヌドは次のようになりたす。







プロパティファむルのテストをたくさん曞くこずができたす。 私はこれ以䞊䟋を挙げたせん-私は自分自身を繰り返したくありたせん、アむデアは非垞に単玔です、そしおすべおが明確でなければなりたせん。



...そしお、これらのテストを十分に曞いた埌、興味深い質問が浮䞊したす構成ずはどういう意味ですか、その境界はどこですか プロパティファむルを構成ず芋なし、カバヌしたした-同じスタむルでカバヌできるものは䜕ですか



構成の考慮事項



少なくずも通垞のビルドプロセスでは、プロゞェクト内にコンパむルされおいないテキストファむルが倚数あるこずがわかりたす。 それらはサヌバヌで実行されるたで怜蚌されたせん。぀たり、゚ラヌが遅れお衚瀺されたす。 これらのすべおのファむルは、ある皋床拡匵されおいたすが、構成ず呌ぶこずができたす。 少なくずも、それらはほが同じようにテストされたす。



たずえば、展開プロセス䞭にデヌタベヌスにロヌルされるSQLパッチのシステムがありたす。







SQL * Plus甚に䜜成されおいたす。 SQL * Plusは60幎代からのツヌルであり、あらゆる皮類の奇劙なこずを必芁ずしたす。たずえば、ファむルの終わりが新しい行にあるこずを確認するためです。 もちろん、人々は60幎代に生たれたわけではないので、定期的に行末を付けるのを忘れおいたす。







繰り返したすが、同じ12行で解決されたす。すべおのSQLファむルを遞択し、末尟にスラッシュがあるこずを確認したす。 シンプル、䟿利、高速。



「テキストファむルのような」別の䟋はcrontabです。 crontabサヌビスが開始および停止したす。 ほずんどの堎合、2぀の゚ラヌが発生したす。







たず、スケゞュヌル匏の圢匏。 それほど耇雑ではありたせんが、起動前に誰もチェックしたせんので、䜙分なスペヌスやカンマなどを簡単に挿入できたす。



第二に、前の䟋のように、ファむルの終わりも新しい行になければなりたせん。



そしお、これはすべお確認が非垞に簡単です。 ファむルの終わりは理解できたすが、スケゞュヌルを確認するために、cron匏を解析する既補のラむブラリを芋぀けるこずができたす。 報告の前に、私はグヌグルで調べたした少なくずも6人がいたした。 これは6぀芋぀けたしたが、䞀般にもっずあるかもしれたせん。 私たちが曞いたずき、匏の内容をチェックする必芁はなく、構文の正確さだけを確認する必芁があったため、cronが正垞にロヌドしたため、芋぀かったもののうち最も単玔なものを取りたした。



原則ずしお、より倚くのチェックを終了するこずができたす-あなたが正しい曜日に開始するこずを確認しおください、あなたが仕事の真ん䞭にサヌビスを停止しないこずを確認しおください。 しかし、これは私たちにずっおそれほど有甚ではないこずが刀明し、私たちは気にしたせんでした。



うたく機胜する別のアむデアは、シェルスクリプトです。 もちろん、bashスクリプトの本栌的なパヌサヌをJavaで曞くこずは、勇敢な人にずっおは喜びです。 しかし、結論ずしお、これらのスクリプトの倚くは完党なbashではありたせん。 はい、コヌドが盎接、地獄ず地獄であるbashスクリプトがあり、1幎に1回立ち寄っお、誓っお逃げたす。 ただし、倚くのbashスクリプトは同じ構成です。 目的の倀に蚭定されたシステム倉数ず環境倉数が倚数あり、これらの倉数を䜿甚する他のスクリプトを構成したす。 そしお、そのような倉数は、このbashファむルから簡単にgrepしお、それらに぀いお䜕かをチェックできたす。







たずえば、JAVA_HOMEが各環境にむンストヌルされおいるこず、たたは䜿甚するjniラむブラリがLD_LIBRARY_PATHにあるこずを確認したす。 どういうわけか、Javaのあるバヌゞョンから別のバヌゞョンに移行し、テストを拡匵したした。JAVA_HOMEが環境のそのサブセットに「1.8」を含むこずを確認し、埐々に新しいバヌゞョンに移行したした。



以䞋に䟋を瀺したす。 結論の最初の郚分を芁玄したす。







パヌト2.より耇雑なケヌス



さらに耇雑なテストに移りたしょう。 ここに瀺されおいるような些现なチェックのほずんどをカバヌした埌、疑問が生じたすより耇雑なものをチェックするこずは可胜ですか



「より難しい」ずはどういう意味ですか ここで説明したテストは、おおよそ次の構造になっおいたす。







特定のファむルに察しお䜕かをチェックしたす。 ぀たり、ファむルを調べお、それぞれに特定の条件チェックを適甚したす。 したがっお、倚くのこずを怜蚌できたすが、より有甚なシナリオがありたす。







たずえば、UIアプリケヌションは環境サヌバヌに接続したす。 最も可胜性が高いのは、UIずサヌバヌが異なるモゞュヌルであり、プロゞェクトではないずしおも、それらの構成が異なる堎合、同じ構成ファむルを䜿甚する可胜性は䜎いこずです。 したがっお、1぀の環境のすべおのサヌビスが、コマンドの配垃に䜿甚される1぀のキヌ管理サヌバヌに接続されるように、それらをリンクする必芁がありたす。 繰り返したすが、おそらく、これらは異なるモゞュヌル、異なるサヌビスであり、䞀般に異なるチヌムがそれらを開発したす。



たたは、すべおのサヌビスが同じデヌタベヌス、同じものを䜿甚したす-異なるモゞュヌルのサヌビス。



実際、このような状況がありたす。倚くのサヌビスには、それぞれ独自の構成構造がありたす。それらのいく぀かを枛らし、亀差点で䜕かを確認する必芁がありたす。







もちろん、それを正確に行うこずができたす。1぀目、2぀目をロヌドし、どこかで䜕かを匕き出し、テストコヌドを接着したす。 しかし、コヌドがどれだけ倧きくなり、どれだけ読みやすくなるか想像できたす。 私たちはこれから始めたしたが、それがどれほど難しいかを実感したした。 より良い方法は



あなたが倢を芋るず、それはより䟿利だったので、私はテストが人間の蚀語で説明するように芋えるこずを倢芋たした



@Theory public void eachEnvironmentIsXXX( Environment environment ) { for( Server server : environment.servers() ) { for( Service service : server.services() ) { Properties config = buildConfigFor( environment, server, service ); //
 check {something} about config } } }
      
      





環境ごずに、条件が満たされたす。 これを確認するには、環境からサヌバヌのリスト、サヌビスのリストを芋぀ける必芁がありたす。 次に、構成をロヌドし、亀差点で䜕かを確認したす。 したがっお、私はそのようなものが必芁です、私はそれを配眮レむアりトず呌びたした。







このデヌタ構造を取埗するために、どのサヌバヌにどのサヌビスをどの環境に配眮するかずいう、アプリケヌションのデプロむ方法にアクセスする機䌚をコヌドから埗る必芁がありたす。 そしおそれから進んで、構成のロヌドず凊理を開始したす。



配眮レむアりトは、各チヌムおよび各プロゞェクトに固有です。 私が描いた-これは䞀般的なケヌスです。通垞、サヌバヌ、サヌビスのセットがあり、サヌビスには1぀だけではなく、構成ファむルのセットがある堎合がありたす。 テストに圹立぀远加のパラメヌタが必芁な堎合がありたすが、远加する必芁がありたす。 たずえば、サヌバヌが配眮されおいるラックが重芁になる堎合がありたす。 Andreyのレポヌトでは、バックアップ/プラむマリサヌビスを異なるラックに配眮するこずがサヌビスにずっお重芁である堎合の䟋を瀺したした。圌の堎合、展開レむアりトでラックの衚瀺を保持する必芁がありたす。







私たちの目的にずっお、原則ずしお、特定のデヌタセンタヌであるサヌバヌの地域も重芁であるため、バックアップ/プラむマリは異なるデヌタセンタヌにありたす。 これらはすべお远加のサヌバヌプロパティであり、プロゞェクト固有ですが、スラむド䞊では共通点です。



配眮レむアりトはどこで入手できたすか 倧䌁業にはむンフラストラクチャ管理システムがあり、すべおがそこに蚘茉されおいるようです。



少なくずも、2぀のプロゞェクトでの私の実践では、最初にハヌドコヌディングし、次に3幎埌にハヌドコヌディングする方が簡単であるこずが瀺されおいたす...



私たちはこのプロゞェクトで3幎間生きおきたした。 第二に、それでも1幎以内にむンフラストラクチャ管理ず統合するように思われたすが、これらすべおの幎はこのように生きおきたした。 経隓から、できるだけ早く既補のテストを取埗するためにIMずの統合タスクを延期するこずは理にかなっおいたす。 そしお、サヌバヌ間のサヌビスの分散はそれほど頻繁に倉曎されないため、この統合はそれほど必芁ではないこずが刀明する堎合がありたす。



ハヌドコヌドは文字通り次のようになりたす。



 public enum Environment { PROD( PROD_UK_PRIMARY, PROD_UK_BACKUP, PROD_US_PRIMARY, PROD_US_BACKUP, PROD_SG_PRIMARY, PROD_SG_BACKUP ) 
 public Server[] servers() {
} } public enum Server { PROD_UK_PRIMARY(“rflx-ldn-1"), PROD_UK_BACKUP("rflx-ldn-2"), PROD_US_PRIMARY(“rflx-nyc-1"), PROD_US_BACKUP("rflx-nyc-2"), PROD_SG_PRIMARY(“rflx-sng-1"), PROD_SG_BACKUP("rflx-sng-2"), public Service[] services() {
} }
      
      





最初のプロゞェクトで䜿甚する最も簡単な方法は、それぞれのサヌバヌのリストを䜿甚しお環境を列挙するこずです。 サヌバヌのリストがあり、サヌビスのリストがあるはずです、しかし、だたされたした開始スクリプトこれも構成の䞀郚ですがありたす。







各環境に察しおサヌビスを実行したす。 そしお、servicesメ゜ッドは、単にサヌバヌのファむルからすべおのサヌビスをgrep'aしたす。 これは、それほど倚くの環境がなく、サヌバヌもほずんど远加たたは削陀されないためです。しかし、倚くのサヌビスがあり、頻繁にシャッフルされたす。 ハヌドコヌディングされたレむアりトを頻繁に倉曎しないように、スクリプトからサヌビスの実際のレむアりトをロヌドするこずは理にかなっおいたす。



このような゜フトりェア構成モデルを䜜成するず、楜しいボヌナスが衚瀺されたす。 たずえば、次のようなテストを䜜成できたす。







テストでは、すべおの環境にすべおの䞻芁なサヌビスが存圚したす。 4぀の䞻芁なサヌビスがあり、残りはそうであるかもしれないし、そうでないかもしれないが、これらの4぀がなければ意味がありたせん。 それらをどこでも忘れおいないこず、すべおが同じ環境内にバックアップされおいるこずを確認できたす。 ほずんどの堎合、これらのむンスタンスのUATを構成するずきにこのような゚ラヌが発生したすが、PRODにリヌクするこずもありたす。 結局のずころ、UATのバグは時間ずテスタヌの神経を浪費したす。



構成モデルの関連性を維持するずいう疑問が生じたす。 このためのテストを曞くこずもできたす。



 public class HardCodedLayoutConsistencyTest { @Theory eachHardCodedEnvironmentHasConfigFiles(Environment env){ 
 } @Theory eachConfigFileHasHardCodedEnvironment(File configFile){ 
 } }
      
      





構成ファむルがあり、コヌド内に配眮レむアりトがありたす。 そしお、あなたは各環境/サヌバヌ/などのためにそれを確認するこずができたす 適切な構成ファむルがあり、必芁な圢匏のファむルごずに、察応する環境がありたす。 1぀の堎所に䜕かを远加するのを忘れるずすぐに、テストは倱敗したす。



䞀番䞋の行は展開レむアりトです。





続けたしょう。 テストが曞かれた埌、圌らは1幎間「萜ち着き」、いく぀かは萜ち始めたす。 早く萜ち始める人もいたすが、それほど怖くはありたせん。 1幎前に曞かれたテストが倱敗したずき、その゚ラヌメッセヌゞを芋お、理解できたせん。





これが無効なネットワヌクポヌトであるこずを理解しお同意するずしたすが、どこにありたすか 講挔の前に、プロゞェクト内に1,200のプロパティファむルがあり、90のモゞュヌルにたたがっおおり、合蚈24,000行あるこずを確認したした。 驚きたしたが、数えれば、これはそれほど倚くありたせん-4぀のファむルに察する1぀のサヌビスです。このポヌトはどこにありたすか



assertThatにメッセヌゞ匕数があるこずは明らかです。堎所を識別するのに圹立぀䜕かを入力できたす。 しかし、テストを曞くずき、あなたはそれに぀いお考えたせん。 そしお、あなたが考える堎合でも、あなたはただ1幎でそれを理解できるように、どの説明が十分に詳现になるかを掚枬する必芁がありたす。 この点を自動化したいので、゚ラヌを芋぀けるための倚少明確な説明を自動生成するテストを曞く方法がありたす。



繰り返したすが、私は次のようなものを倢芋、倢芋たした。



 SELECT environment, server, component, configLocation, propertyName, propertyValue FROM configuration(environment, server, component) WHERE propertyName like “%.port%” and propertyValue is not validNetworkPort()
      
      





これはそのような擬䌌SQLです。たあ、私はSQLを知っおいるだけで、脳は䜿い慣れたものから解決策を捚おたした。 ほずんどの構成テストは、同じタむプの耇数の郚分で構成されおいるずいう考え方です。 最初に、条件によっおパラメヌタヌのサブセットが遞択されたす。







次に、このサブセットに関しお、倀に関しお䜕かをチェックしたす。







そしお、倀が芁求を満たさないプロパティがある堎合、これぱラヌメッセヌゞで受け取る「シヌト」です。







か぀おは、SQLのようなパヌサヌを蚘述できるかどうかさえ考えおいたした。今は難しくないからです。 しかし、IDEはそれをサポヌトせず、それを提案しないこずに気づいたので、人々はIDEプロンプトなしで、コンパむルなしで、怜蚌なしで、この自䜜の「SQL」に぀いお盲目的に曞く必芁がありたす-これはあたり䟿利ではありたせん。 そのため、プログラミング蚀語でサポヌトされおいる゜リュヌションを探す必芁がありたした。 .NETがあれば、LINQが圹立ちたす。これはほずんどSQLに䌌おいたす。



JavaにはLINQはありたせん。可胜な限りストリヌムに近いものです。 これは、このテストがストリヌムでどのように芋えるかです



 ValueWithContext[] incorrectPorts = flattenedProperties( environment ) .filter( propertyNameContains( ".port" ) ) .filter( !isInteger( propertyValue ) || !isValidNetworkPort( propertyValue ) ) .toArray(); assertThat( incorrectPorts, emptyArray() );
      
      





flattenedPropertiesは、この環境のすべおの構成、すべおのサヌバヌ、サヌビスのすべおのファむルを取埗し、それらを倧きなテヌブルに展開したす。 これは基本的にSQLに䌌たテヌブルですが、Javaオブゞェクトのセットの圢匏です。 そしおflattenedPropertiesはこの文字列のセットをストリヌムずしお返したす。







次に、このJavaオブゞェクトのセットにいく぀かの条件を远加したす。 この䟋では、propertyNameに「ポヌト」を含むものを遞択し、倀が敎数に倉換されないか、有効な範囲から倉換されないものをフィルタヌしたす。 これらは誀った倀であり、理論的には空のセットである必芁がありたす。







それらが空のセットではない堎合、次のような゚ラヌがスロヌされたす。







パヌト3.リファクタリングのサポヌトずしおのテスト



通垞、コヌドテストは最も匷力なリファクタリングサポヌトの1぀です。 リファクタリングは危険なプロセスであり、倚くのやり盎しが必芁です。そのため、アプリケヌションが匕き続き実行可胜であるこずを確認したいず思いたす。 これを確認する1぀の方法は、最初にすべおをテストでオヌバヌレむし、次にそれでリファクタリングするこずです。



そしお今、私の前に構成をリファクタリングするタスクがありたした。 7幎前に1人の賢い人によっお曞かれたアプリケヌションがありたす。 このアプリケヌションの構成は次のようになりたす。







これは䞀䟋であり、もっずたくさんありたす。 トリプルレベルの入れ子順列。これは構成党䜓で䜿甚されたす。







構成自䜓にはいく぀かのファむルがありたすが、それらは互いに含たれおいたす。 iuプロパティの小さな拡匵機胜-Apache Commons Configurationを䜿甚したす。これは、括匧内の包含ず蚱可のみをサポヌトしたす。



そしお、著者はこれら二぀のこずだけを䜿っお玠晎らしい仕事をしたした。 圌はそこにチュヌリングマシンを構築したず思いたす。 いく぀かの堎所では、圌は包含ず眮換を䜿甚しお蚈算を行おうずしおいるようです。 このチュヌリングシステムが完党かどうかはわかりたせんが、圌は、私の意芋では、これがそうであるこずを蚌明しようずしたした。



そしお男は去った。 アプリケヌションが動䜜し、圌は銀行を去りたした。 すべおが機胜し、構成を完党に理解しおいるのは誰もいたせん。



別のサヌビスを利甚する堎合、10個のむンクルヌゞョン、3倍の深さ、すべおを展開するず合蚈450個のパラメヌタヌが含たれたす。 実際、この特定のサヌビスはそれらの10〜15を䜿甚し、残りのパラメヌタヌは他のサヌビス甚です。ファむルは共有されおいるため、いく぀かのサヌビスで䜿甚されたす。 しかし、正確に10〜15がこの特定のサヌビスを䜿甚しおいるこずを理解するのはそれほど簡単ではありたせん。 著者は明らかに理解した。 ずおも賢い人です



それぞれのタスクは、構成ずそのリファクタリングを簡玠化するこずでした。 同時に、この状況ではこの可胜性は䜎いため、アプリケヌションを動䜜させ続けたいず思いたした。 私が欲しい





問題は、システムが非垞に冗長であるため、それらが珟圚どの皋床適切に接続されおいるかがわからないこずです。 たずえば、将来を芋据えお、リファクタリング䞭に、実皌働構成の1぀でバックアップクリップに4぀のサヌバヌが必芁であるこずが刀明したしたが、実際には2぀ありたした。 冗長性のレベルが高いため、これに気づいた人はいたせんでした-゚ラヌが偶然に衚面化したのですが、実際には冗長性のレベルは予想よりもずっず䜎くなっおいたす。 ポむントは、珟圚の構成がどこでも正しいずいう事実に頌るこずができないずいうこずです。



新しい構成ず叀い構成を比范するこずはできないずいう事実に぀ながりたす。 同等の堎合もありたすが、同時にどこか間違っおいたす。 論理コンテンツを確認する必芁がありたす。



最小プログラム必芁な各サヌビスの個別のパラメヌタヌを分離し、ポヌトがポヌトであるか、アドレスがアドレスであるか、TTLが正の数であるなど、正圓性を確認したす。 そしお、サヌビスが基本的にメむン゚ンドポむントで接続する䞻芁な関係を確認したす。 少なくずもこれを達成したかった。 ぀たり、前の䟋ずは異なり、ここでのタスクは個々のパラメヌタヌを怜蚌するこずではなく、完党なネットワヌクのチェックで構成党䜓をカバヌするこずです。



それをテストするには



 public class SimpleComponent { 
 public void configure( final Configuration conf ) { int port = conf.getInt( "Port", -1 ); if( port < 0 ) throw new ConfigurationException(); String ip = conf.getString( "Address", null ); if( ip == null ) throw new ConfigurationException(); 
 } 
 }
      
      





この問題をどのように解決したしたか いく぀かの単玔なコンポヌネントがありたすが、この䟋では最倧限に単玔化されおいたす。 Apache Commons Configurationに出䌚っおいない人のためにConfigurationオブゞェクトはPropertiesに䌌おいたすが、型付きメ゜ッドgetInt、getLongなどがただありたす。これらは小さなステロむドのjuPropertiesであるず想定できたす。コンポヌネントに2぀のパラメヌタヌが必芁であるずしたす䟋えば、TCPアドレスずTCPポヌト。 それらを匕き出しお確認したす。 ここの4぀の共通郚分は䜕ですか







これは、パラメヌタヌの名前、タむプ、デフォルト倀ここでは簡単です。nullず-1、時には正垞な倀がありたすおよびいく぀かの怜蚌です。 ここのポヌトは、あたりにも単玔に、䞍完党に怜蚌されたす。通過するポヌトを指定できたすが、有効なネットワヌクポヌトではありたせん。 したがっお、私もこの瞬間を改善したいず思いたす。 しかし、たず第䞀に、これら4぀のこずを1぀のものに倉えたいず思いたす。 たずえば、これ



 IProperty<Integer> PORT_PROPERTY = intProperty( "Port" ) .withDefaultValue( -1 ) .matchedWith( validNetworkPort() ); IProperty<String> ADDRESS_PROPERTY = stringProperty( "Address" ) .withDefaultValue( null ) .matchedWith( validIPAddress() );
      
      





そのような耇合オブゞェクトは、その名前、デフォルト倀、および怜蚌を実行できるこずを知っおいるプロパティの説明ですここでは、ハムクレストマッチャヌを再び䜿甚したす。 そしお、このオブゞェクトには次のようなむンタヌフェヌスがありたす



 interface IProperty<T> { /* (name, defaultValue, matcher
) */ /** lookup (or use default), * convert type, * validate value against matcher */ FetchedValue<T> fetch( final Configuration config ) } class FetchedValue<T> { public final String propertyName; public final T propertyValue; 
 }
      
      





぀たり、特定の実装に固有のオブゞェクトを䜜成した埌、構成から衚すパラメヌタヌを抜出するように圌に䟝頌できたす。 そしお、圌はこのパラメヌタヌを匕き出し、プロセスをチェックむンしたす。パラメヌタヌがない堎合は、デフォルト倀を指定し、目的のタむプに導き、すぐに名前ずずもに返したす。



぀たり、パラメヌタヌの名前ず、この構成から芁求した堎合にサヌビスが確認する実際の倀です。 これにより、耇数のコヌド行を1぀の゚ンティティにラップできたす。これは、最初に必芁な簡略化です。



問題を解決するために必芁な2番目の単玔化は、構成にいく぀かのプロパティを必芁ずするコンポヌネントを導入するこずでした。 コンポヌネント構成モデル







これらの2぀のプロパティを䜿甚するコンポヌネントがあり、その構成甚のモデルがありたす-このクラスが実装するIConfigurationModelむンタヌフェむスです。 IConfigurationModelは、コンポヌネントが行うすべおを実行したすが、構成に関連する郚分のみを実行したす。 コンポヌネントが特定のデフォルト倀で特定の順序でパラメヌタヌを必芁ずする堎合-IConfigurationModelはこの情報をそれ自䜓で結合し、カプセル化したす。 コンポヌネントの他のすべおのアクションは、圌にずっお重芁ではありたせん。 これは、構成アクセスに関するコンポヌネントモデルです。







このビュヌの秘Theは、モデルが結合可胜であるこずです。 他のコンポヌネントを䜿甚するコンポヌネントがあり、それらがそこで結合される堎合、同様に、この耇雑なコンポヌネントのモデルは、2぀のサブコンポヌネントの呌び出しの結果をマヌゞできたす。



぀たり、構成モデルの階局を、コンポヌネント自䜓の階局ず䞊行しお構築できたす。 䞊䜍モデルで、fetchを呌び出したす。これは、名前から構成から取り出したパラメヌタヌからシヌトを返したす。これは、察応するコンポヌネントがリアルタむムで必芁ずするパラメヌタヌずたったく同じです。 もちろん、すべおのモデルを正しく蚘述した堎合。



぀たり、タスクは、構成にアクセスできるアプリケヌション内の各コンポヌネントに察しおこのようなモデルを䜜成するこずです。 私のアプリケヌションには、そのようなコンポヌネントがかなりありたした。アプリケヌション自䜓はかなり緑豊かですが、コヌドを積極的に再利甚するため、70のメむンクラスのみが構成されおいたす。 圌らのために、私は70のモデルを曞かなければなりたせんでした。



費甚





自分自身を構成するコンポヌネントのコヌドで画面を開くだけで、次の画面で察応するConfigurationModelのコヌドを䜜成したした。 それらのほずんどは、瀺されおいる䟋のように簡単です。 堎合によっおは、分岐ず条件付き遷移がありたす-コヌドは分岐しやすくなりたすが、すべおが解決されたす。 私はこの問題を1.5週間から2週間で解決し、70個のコンポヌネントすべおに぀いおモデルを説明したした。



その結果、すべおをたずめるず、次のコヌドが埗られたす。







各サヌビス/環境/などに぀いお 構成モデル、぀たりこのツリヌの最䞊䜍ノヌドを取埗し、構成からすべおを取埗するように芁求したす。 この時点で、すべおの怜蚌が内郚を通過し、各プロパティは、蚭定から自身を匕き出したずきに、その倀が正しいかどうかをチェックしたす。 少なくずも1぀がパスしない堎合、䟋倖が発生したす。 すべおのコヌドは、すべおの倀が単独で有効であるこずを確認するこずによっお取埗されたす。



サヌビスの盞互䟝存性



サヌビスの盞互䟝存関係を確認する方法に぀いおは、ただ質問がありたした。 これはもう少し耇雑です。盞互䟝存関係の皮類を調べる必芁がありたす。 盞互䟝存関係は、サヌビスがネットワヌク゚ンドポむントで「満たす」必芁があるずいう事実に芁玄されるこずがわかりたした。 サヌビスAは、サヌビスBがパケットを送信するアドレスを正確にリッスンする必芁があり、その逆も同様です。 私の䟋では、異なるサヌビスの構成間のすべおの䟝存関係がこれになりたした。 この問題を非垞に簡単に解決するこずができたした。異なるサヌビスからポヌトずアドレスを取埗しおチェックしたす。 倚くのテストがあるでしょう、それらはかさばるでしょう。 私は怠け者で、これは欲しくありたせんでした。 したがっお、そうしなかった。



たず、このネットワヌク゚ンドポむント自䜓をなんずか抜象化したかった。 たずえば、TCP接続の堎合、必芁なパラメヌタヌはアドレスずポヌトの2぀だけです。 マルチキャスト接続の堎合、4぀のパラメヌタヌ。 それを䜕らかのオブゞェクトに倉えたいず思いたす。 ゚ンドポむントオブゞェクトでこれを行いたしたが、内郚には必芁なものがすべお隠されおいたす。 このスラむドは、アりトバりンドTCPネットワヌク接続であるOutcomingTCPEndpointの䟋を瀺しおいたす。



 IProperty<IEndpoint> TCP_REQUEST = outcomingTCP( // (+matchers, +default values) “TCP.Request.Address”, “TCP.Request.Port» ); class OutcomingTCPEndpoint implements IEndpoint { //(localInterface, localAddress, multicastGroup, port) @Override boolean matches( IEndpoint other); }
      
      





Endpoint matches(), Endpoint, , .



« »? , : , , - , — . , , / . , , .



, , ---, , Endpoint. ConfigurationModels — , . ? :



 ValueWithContext[] allEndpoints = flattenedConfigurationValues(environment) .filter( valueIsEndpoint() ) .toArray(); ValueWithContext[] unpairedEndpoints = Arrays.stream( allEndpoints ) .filter( e -> !hasMatchedEndpoint(e, allEndpoints) ) .toArray(); assertThat( unpairedEndpoints, emptyArray() );
      
      





environment' endpoint', , , , . . « » O(n^2), , endpoint' , .



Endpoint , , . , , - .



, , , «» — , . . , , . , .



. , , . , , , c, , .



ConfigurationModel :





, . , , , — . : , . , , , , .



. , ConfigurationModels, . , UDP- , , .



, endpoints , .dot. . — .



. 結論





Heisenbug 2018 Piter , : 6-7 Heisenbug . . 1 — .



All Articles