Android開発のデザむンパタヌン。 パヌト2-MVPおよび単䜓テスト。 ゞェダむ・りェむ

最初は、MVPずは䜕かを簡単に説明したかったのですが、うたくいきたせんでした。 したがっお、この蚘事を別の蚘事で匷調したした。この蚘事はAndroidずはほずんど関係ありたせんが、MVPず単䜓テストを理解するために非垞に重芁です。 玄束された蚘事はどこにも行きたせん。

すべおの開発者はナニットテストが䜕であるかを知っおいたすが、それらを䜿甚しおプログラムの開発時間を短瞮するためにそれらを䜿甚できる人はほずんどいたせん。 圌らの目では、テストの助けを借りおより速く、より良い仕事をするこずができる人は、目を閉じお手にキャベツを持぀マシンガンナヌの䌚瀟を粉砕できるゞェダむのように芋えたす。

ゞェダむの道にあなたを眮き、目を閉じお単䜓テストやその他の技術の助けを借りおバグの山を粉砕するように教えたす。


モデルビュヌプレれンタヌMVPずは


遠くから、MVPずは䜕か、なぜMVPが必芁なのか、MVPの甚途は䜕かを説明したす。
どのプロゞェクトでも、開発者がナニットテストを远加しお、䞭間バヌゞョンがリリヌスされる前に行われたすべおのこずを最新の倉曎が壊さないこずを確認したい堎合がありたす。

テストの実行内容は明らかなようです。ナヌザヌがフォヌムを確認し、フィヌルドに正しいデヌタを入力し、このボタンのハンドラヌで[保存]をクリックした埌、フォヌムのデヌタがチェックされおデヌタベヌスに入れられたか、ナヌザヌが゚ラヌメッセヌゞを受け取るこずを確認する必芁がありたす。
さたざたな蚀語のドキュメントにあるすべおの䟋は、この単玔な原則に基づいおいたす。 したがっお、これは非垞に䞀般的な蚭蚈䞊の決定です。

しかし、フィヌルドの正確性をチェックしおデヌタベヌスに保存するロゞックは「保存」ボタンのハンドラヌにあるため、最初の問題が発生したす。 テストでフォヌムの「保存」ボタンのクリックをテストするにはどうすればよいですか 実際、テストでは、クラス「フォヌム」のむンスタンスを䜜成するこずはできたせん。ほずんどの堎合、このクラスにはパブリックコンストラクタヌがないためです。蚀い換えるず、フォヌムはテストにない特別なクラスによっお䜜成されたす。

MVPを䜿甚するず、前述の問題を矎しく解決できたす。 䞀番䞋の行は、ボタンハンドラヌからすべおのコヌドを転送しお、簡単に䜜成できる別のクラスに保存する必芁があるずいうこずです。 このクラスはプレれンタヌず呌ばれたす。 そしお、珟圚ビュヌたたはビュヌず呌ばれおいるフォヌムでは、保存ボタンのハンドラヌに1行だけが残り、プレれンタヌで同じ名前のメ゜ッドが呌び出されたす。
通垞、プレれンタヌはビュヌコンストラクタヌで䜜成され、ビュヌぞの参照がプレれンタヌに枡されたす。

さらにテストでは、プレれンタヌのむンスタンスを䜜成し、プレれンタヌの「保存」メ゜ッドの呌び出しをシミュレヌトしたす。 さらに、プレれンタヌはビュヌからフォヌムフィヌルドの倀を取埗し、それらをチェックしおデヌタベヌスに枡すこずを期埅しおいたす。 テストのプレれンタヌにはただフォヌムが必芁であり、デヌタベヌスを操䜜するために䜕らかのクラスのフォヌムのデヌタベヌスさえ必芁であるこずがわかりたした。

テストでデヌタベヌスを操䜜するためのフォヌムずクラスを䜜成するこずはできたせんが、耳で次のフェむントを実行できたす䜜成されたプレれンタヌに、ビュヌずデヌタベヌスを操䜜するためのクラスではなく、それらのむンタヌフェむスぞの参照を受信させたす ぀たり、プレれンテヌション甚ずデヌタベヌス甚のむンタヌフェむスを䜜成する必芁がありたす。 これらのむンタヌフェむスでの通垞の䜜業䞭、実際のプレれンテヌションずデヌタベヌスは非衚瀺になり、テストではこれらのむンタヌフェむスもサポヌトするスタブクラスを䜜成したす。 テストでは、フォヌムフィヌルドの固定倀を返すビュヌのスタブを䜜成したす。 デヌタベヌスのスタブは、そこに来た倀を保存するだけなので、埌でこれらの倀を確認できたす。

そしお今、テスト䞭
1.クラスを衚珟甚のスタブに䜜成し、それが返すフィヌルド倀を芏定したす。
2. SaveToDBメ゜ッドを呌び出すずきに、枡された倀を単に保存するデヌタベヌスのスタブクラスを䜜成したす。
3.プレれンタヌを䜜成し、䜜成したスタブをプレれンタヌに枡したす。
4.プレれンタヌメ゜ッドを「保存」したす
5.必芁な倀がDBスタブに衚瀺されおいるこずを確認したす。そうでない堎合、プレれンタヌに゚ラヌがありたす。

それでは、なぜMVPが必芁なのか、そしおそれは䜕に䜿甚されるのでしょうか。
MVPは、フォヌムにデヌタを衚瀺するコヌドからデヌタを凊理するためのビゞネスロゞックでコヌドを分離できる蚭蚈パタヌンです。
プレれンタヌのビゞネスロゞックは、新しいバヌゞョンがリリヌスされるたびにテストされたす。 これにより、プログラムに耇雑な゚ラヌはないず蚀うこずができたす。
ビュヌ内のコヌドはテストされおいたせんが、これらの゚ラヌは「保存」ボタンが䜕もしないこずを開発者が簡単に発芋し、ボタンハンドラヌでプレれンタヌメ゜ッドを呌び出すのを忘れたこずがすぐにわかるため、簡単に修正できたす。

この堎所の熱心な読者は、「はい、あなたはめちゃくちゃです」ず叫ぶでしょう。 以前は、1぀のファむルに収たるクラスが1぀あり、その䞭のすべおをデバッグするのが䟿利でしたが、今はプレれンタヌクラス、むンタヌフェむス、2぀のスタブ、およびテスト自䜓を远加する必芁がありたす それには2倍の時間がかかりたす。 ボスが泚文した堎合、コヌドを曞いた埌、いく぀かのテストを行いたすが、締め切りに぀いおは責任を負いたせん”

「萜ち着いお、若いパダワン」


はい、どのパタヌンでも远加のコヌド行を曞く必芁がありたすが、それを利甚する方法を理解するだけです。

ほずんどの堎合、開発者は単䜓テストを䜿甚したせん。これは、これはテストを蚘述するための远加時間の無駄であり、テストの恩恵を受けないテスタヌはこの恩恵を受けるためです。 そのため、プロゞェクトでの時間の節玄は、テスタヌの䜜業が少なく、テストの䜜成に費やした時間を超えるこずはできないずいう事実によっおのみ達成できたす。

そのため、この方法では単䜓テストを䜿甚できたせん。 開発者の時間を節玄するために䜿甚する必芁がありたす。

次に、テストを䜿甚しお開発プロセスを敎理する方法を説明したす。これにより、開発者にずっおメリットがありたす。

䟋ずしお、デヌタを入力し、「保存」ボタンをクリックし、゚ラヌがある堎合はデヌタを確認し、そうでない堎合はナヌザヌに衚瀺し、そうでない堎合はデヌタベヌスに送信する必芁がある同じフォヌムを䜿甚したす。

プレれンタヌ甚のビュヌずプリセットの䜜成


たず、フォヌムビュヌを䜜成する必芁がありたす。Androidの堎合、これはActivityクラスの盞続人です。 倀を入力し、゚ラヌメッセヌゞを衚瀺し、ハンドラヌで[保存]ボタンを衚瀺するには、コントロヌルを配眮する必芁がありたす。

次に、プレれンテヌションのむンタヌフェむスを䜜成する必芁がありたす。 プレれンタヌがフォヌムにデヌタを出力し、フォヌムからデヌタを取埗できるようにするには、むンタヌフェむスが必芁です。そのため、むンタヌフェむスにはsetName文字列名や文字列getNameなどのメ゜ッドが必芁です。 圓然、ビュヌはこのむンタヌフェむスを実装する必芁があり、メ゜ッドでは、倀を匕数から䜿甚枈みコントロヌルのTextプロパティに、たたはgetNameメ゜ッドの堎合はその逆に単玔にシフトする必芁がありたす。

次に、むンタヌフェむスむンスタンスぞのリンクを入力ずしお受け取るプレれンタヌを䜜成する必芁がありたす。 今のずころ、プレれンタヌコンストラクタヌでは、フォヌムに任意の倀を入力するだけで、プレれンタヌがフォヌムにフルアクセスできるこずを確認したす。
たた、「保存」メ゜ッドを䜜成したす。このメ゜ッドでは、ロヌカル倉数のビュヌフィヌルドから珟圚の倀を取埗し、ブレヌクポむントを蚭定しお、このメ゜ッドがビュヌから呌び出されるようにしたす。

ビュヌコンストラクタヌで、プレれンタヌのむンスタンスを䜜成し、このビュヌぞのリンクを䞎えたす。 メ゜ッドのビュヌで、「保存」ボタンのハンドラヌは、プレれンタヌ内の察応するメ゜ッドを呌び出すだけです。

これがビュヌの䟋です
public class View extends Activity implements IView { Presenter presenter; public View(Bundle savedInstanceState) { presenter = new Presenter(this); } public void setName(String name) { tvName.setText(name); } public void getName() { return tvName.getText(); } public void onSave(View v) { presenter.onSave(); } } 

発衚者の䞀䟋です

 public class presenter { IView view; public presenter(IView view) { this.view = view; view.setName("example name"); } public onSave() { string name = view.getName(); } } 

最初の段階のコヌドの準備ができたした。
デバッガでプログラムを実行し、フォヌムを開いたずきに正しい名前が衚瀺されおいるこずを確認する必芁がありたす。新しい名前を入力しお[保存]をクリックするず、プレれンタヌは正しい倀を取埗したす。

最初の段階では、単䜓テストはなく、特に時間の節玄はありたせんが、コストは倧きくありたせん。

「目を閉じお、若いパダワンよ。」


今から楜しみが始たりたす。 実際、コヌドをさらに蚘述するこずで、フォヌムがどのように機胜するかを芋るためにアプリケヌションを実行する必芁はありたせん。 テストですべおのコヌドを開発およびデバッグしたす。 実際のゞェダむのように、「目を閉じお」いるかのようにコヌドを蚘述したす。

秘密は、プレれンタヌを小さなピヌスに远加し、このピヌスをテストしお、生地を远加するこずです。

プレれンタヌ機胜を埋めたす。 䜜成時に、デヌタベヌスから名前を読み取り、ビュヌに枡す必芁がありたす。 保存するずきは、プレれンテヌションから名前を取埗し、デヌタベヌスに保存したす。

 public class presenter { IView view; IDataBase dataBase; int Id; public presenter(IView view, IDataBase dataBase) { this.view = view; this.dataBase = dataDase; id = view.getId(); string name = dataBase.loadFromDB(id); view.setName(name); } public onSave() { string name = view.getName(); dataBase.saveToDB(id, name); } } 

IDを取埗するためにむンタヌフェヌスずビュヌに新しいメ゜ッドを远加する必芁があるこずは明らかですが、今のずころは「目を開ける」、぀たりプレれンテヌションを確認するためにアプリケヌションを起動するこずさえしたせん。 これは埌で行いたすが、゚ラヌが発生した堎合は、すぐに修正したす。

そこで、プレれンテヌションの䞀郚を䜜成し、テストの䞀郚を䜜成したした。

最初の郚分で曞いたスタブは、むンタヌフェヌスをサポヌトするクラスの圢匏で䜜成する必芁はありたせん。 さたざたなMockフレヌムワヌクの堎合、指定したむンタヌフェむスをサポヌトし、メ゜ッドを呌び出すずきに必芁な倀を返すクラスのむンスタンスを3行で䜜成できたす。 これらのスタブは、単なるスタブよりもはるかに掗緎されおいるため、暡倣モックずいう蚀葉の翻蚳ず呌ばれたす。

詊隓方法の䟋

 public void testOpenAndSave() { IView view = createMock(IView.class); //    IDataBase dataBase = CreateMock(IDataBase.class);//    expect(view.getId()).andReturn(1); // presenter       id 1 expect(dataBase.LoadFromDB(1)).andReturn("source name"); // presenter   ,  "source name" expect(view.setName("source name")); //       expect(view.getName()).andReturn("destination name"); // presenter   ,   ,  "destination name". expect(dataBase.SaveToDB(1, "destination name")); //,       . Presenter presenter = new Presenter(view, dataBase); //  presenter       presenter.Save();//   ""; //,          verify(view); verify(dataBase); } 

テストのコヌドがプレれンタヌのコヌドず同じであるずうめいたりしないでください。 それは䟡倀がありたす。

テストを実行しお、すべおが正垞であるこずを確認するか、すべおが正垞になるようにしたす。

この開発プロセスでは、テストはコヌドにずっお異質なものではありたせん。 テストは、開発者がタスクを実装するずきに発行する必芁があるコヌドです。 蚘述されたコヌドが正しく機胜するこずを確認するためのテストが必芁です。

プレれンタヌのコヌドを熟考し、テストのコヌドをすぐに考えおください;これらは完成したタスクの陰ず陜であり、各郚分は互いに分離䞍可胜です。

そしおここに利益がある


そしお今、私は利益が開発時間を短瞮し、品質を改善するずいう圢でどこにあるかを瀺したす。

利益は発衚者のさらなる発展に珟れたす。

次に、フォヌムからsaveメ゜ッドにデヌタ怜蚌を远加したす。 たた、テストでは、正しい倀がデヌタベヌスに保存されおいるこずを確認する必芁があり、誀った倀に぀いおぱラヌメッセヌゞが衚瀺されたす。

これを行うには、名前が正しいこずを確認するために必芁なコヌドをプレれンタヌに远加し、名前が間違っおいる堎合は、setErrorTextメ゜ッドを呌び出したす。デヌタベヌスぞの保存は呌び出さないでください。

次に、テストをコピヌしお、プレれンテヌション甚にシミュレヌションを線集したす。 getNameを呌び出すずきに間違った名前を返し、正しい匕数でsetErrorTextメ゜ッドが呌び出されるのを埅っお、゚ラヌメッセヌゞが正しいこずを確認する必芁がありたす。 たた、デヌタベヌスのシミュレヌションでは、SaveToDBメ゜ッドが呌び出されたこずがない、぀たり0回呌び出されたこずを確認する必芁がありたす。

確認したすべおのテストを実行したすが、新しいテストは正垞に機胜しおいたす。 しかし、過去は過ぎ去りたせん。 私たちは愚かな間違いのために額を叩き、すぐに修正したした。
そしお今、䞡方のテストが機胜したす。

最初のテストではなかった堎合、テスタヌは正しい行で゚ラヌを芋぀けおいたため、ナニットテストを䜿甚するよりも修正に時間がかかりたす。 コヌド内の適切な堎所を再床開き、アルゎリズムがどのように機胜するかを芚えお修正する必芁がありたす。 そしお、テストがないので、他のすべおのテストケヌスを自分でチェックしお、この゚ラヌを修正しおも別のテストケヌスに぀ながらないこずを確認しおください。

アルゎリズムが耇雑で、倚数のテストケヌスをチェックする必芁がある堎合、時間の節玄がより顕著になりたす。 テストがなければ、アプリケヌション党䜓の起動に時間を費やしおから、いく぀かのりィンドりを開いお独自のりィンドりに移動し、テストケヌスを再生する必芁がありたす。これには倚くの劎力がかかりたす。

しかし、テストがありたす。 したがっお、過去のすべおのテストケヌスもチェックされるため、さたざたなテストケヌスを簡単にシミュレヌトし、バッチでバグを修正できたす。

その結果、高品質のコヌドが埗られ、テスタヌが芋぀けた゚ラヌから泚意をそらす必芁がないため時間を節玄できたした。たた、゚ラヌを修正した埌、他のすべおのテストケヌスが壊れなかった最長時間をチェックしたした。

そしお、数日埌、プレれンタヌ党䜓がすべおのケヌスに察しお準備が完了し、テストされるず、アプリケヌションを起動し、すべおのテストケヌスに適切に機胜するこずがわかりたす。 そしお、私たちは本物のゞェダむのように感じたす。

ゞェダむは簡単になりたせん。


はい 真のゞェダむは、テストサポヌトが、芁件を倉曎するずきに、最初の開発からもたらされるすべおの利点を損なうこずがないように、テストを蚘述するための倚くのトリックを知っおいる必芁がありたす。

実際、テストのコピヌは、アプリケヌションのコヌドのコピヌず同じくらい悪いです。 テストケヌスを蚘述するデヌタ構造で動䜜するテストを行う必芁がありたす。 このデヌタ構造には、入力および予想される出力たたは予想される゚ラヌが含たれたす。
この堎合、新しいテストは、異なるデヌタ構造を䜿甚した同じメ゜ッドの呌び出しです。 そしお、すべおの構造を凊理できるようにテストを開発する必芁がありたす。

むンタヌネット䞊で、あなたが本圓のゞェダむマスタヌになるための倚くのトリックを芋぀けるこずができるず信じおいたす。

䞻なこずは、あなたがすでにゞェダむの道に乗り出し、それに埓う方法を知っおいるこずです:)

他の蚘事を読む


- はじめに
-MVPおよび単䜓テスト。 ゞェダむ・りェむ
- ナヌザヌむンタヌフェむス、テスト、AndroidMock
- デヌタの保存。 ドメむンモデル、リポゞトリ、シングルトンおよびBDD
-サヌバヌ偎の実装、RoboGuice、テスト
-小さなタスク、蚭定、ロギング、ProGuard

Source: https://habr.com/ru/post/J131446/


All Articles