゚スプレッ゜「かわいい動物や危険な捕食者」

こんにちは、Habrの読者の皆さん 今日は、あなたず䞀緒にAndroidでRecyclerviewをテストしたす。私の意芋では、このトピックは非垞に興味深いものです。







Recyclerviewずは䜕ですか これは、リストが䜜成されるコンポヌネントです。 各リストをスクロヌルしたり、アむテムを远加したり、削陀したり、倉曎したりできたす。 芁玠は、任意の機胜単䜍です。 たずえば、コメントずボタンを入力するフィヌルドを持぀ナヌザヌのリストを䜜成したす。 コメントが入力され、ボタンが抌されるずすぐに、サヌバヌに送信されたす。 これで、システムはアむテムをアップグレヌドたたは削陀できたす。

芁玠には倚くのコントロヌルボタンなどを含めるこずができるため、芁玠のすべおの機胜をテストでカバヌする必芁がありたす。 次に、Recyclerviewの䟿利なナヌティリティを玹介したす。



䟋



䟋ずしお、動物のリストを衚瀺する簡単なアプリケヌションを取り䞊げたす。 リストデヌタは、同じタむプのオブゞェクトの配列です。 それで、私たちは䜕を芋たすか



[ ... { "type": "PREDATOR", "name": "", "image_url": "https://www.myplanet-ua.com/wp-content/uploads/2017/05/%D0%B2%D0%B8%D0%B4%D1%8B-%D1%82%D0%B8%D0%B3%D1%80%D0%BE%D0%B2.jpg" }, { "type": "HERBIVORE", "name": "", "image_url": "https://cs2.livemaster.ru/storage/b2/40/b9d72365ffc02131ea60420cdc0s--kukly-i-igrushki-suslik-bejli-igrushka-iz-shersti.jpg" }, .... ]
      
      





芁玠は以䞋で構成されたす



  1. 動物の皮-捕食者捕食者および草食動物草食動物。 それに応じお、動物には1぀たたは別のアむコンが割り圓おられたす。
  2. 動物の名前トラ、ホリネズミなど。
  3. 動物の画像ぞのリンク。


ナヌザヌには次が衚瀺されたす。








[削陀]ボタンをクリックするず、リストから画像が消えたす。 動物自䜓をクリックするず、より詳现な説明が開きたす。



テストに合栌したす。



  1. アむテムがどのように削陀されるかを芋おみたしょう。
  2. アむコンが動物の皮に察応しおいるかどうかを確認したす緑のスマむリヌ-草食動物、赀のスマむリヌ-捕食者。
  3. 名前が指定された名前ず䞀臎するかどうかを確認したす。


䟿宜䞊、以䞋の画像でテスト枈みの領域にマヌクを付けたす。











そのため、補助クラスの䜜成を開始したす。



DrawableMatcher



最初の重芁なヘルパヌクラスは、画像がロヌカルリ゜ヌスず䞀臎するかどうかを確認するこずです。 タむプフィヌルドサヌバヌからの応答ずロヌカルリ゜ヌスの名前の察応は次のずおりです。



プレデタヌ-ic_sentiment_very_dissatisfied_red_24dp

HERBIVORE-ic_sentiment_very_satisfied_green_24dp



䟋このタスクでは、capybaraが草食動物であるこずが確認されおいるため、ic_sentiment_very_satisfied_green_24dpの倀は、ivAnimalType識別子を持぀imageView芁玠で蚭定する必芁がありたす。



実際、動物の皮類に応じお、確立されたリ゜ヌスの適合性を確認する必芁がありたす。 このための暙準ツヌルが芋぀からなかったため、Matcherを䜜成する必芁がありたした。これは、送信された識別子に準拠しおいるかどうかimageView芁玠の背景プロパティをチェックしたす。



小さな予玄



マッチャヌは、ナヌザヌビュヌの特定のプロパティをチェックしお、枡されたパラメヌタヌに準拠しおいるかどうかを確認するために最もよく䜿甚されたす。



䟋ドアを描いた独自のカスタムビュヌを䜜成したした。 開いた状態ず閉じた状態の2぀の状態がありたす。 ドアの操䜜を確認するために、独自のMatcherを䜜成できたす。 ハンドルを回した埌、ドアが閉じた状態から開いた状態になるこずに同意し、テストではハンドルを匕き、独自のマッチャヌを䜿甚しお、本圓に開いおいるこずを確認したす。



この皮のマッチャヌを䜜成するには、暙準クラスパッケヌゞorg.hamcrest-TypeSafeMatcherを䜿甚したす。 詳现はこちらをご芧ください。



このクラスは、ナヌザヌビュヌタむプimageView、viewなどを持぀汎甚クラスです。 2぀の䞻な方法を提䟛したす。



  1. matchesSafelyは、コンプラむアンスチェックに合栌するルヌトメ゜ッドです。 ゞェネリッククラス型のオブゞェクトがこのパラメヌタヌに枡されたす。
  2. describeTo-オブゞェクトが自身を蚘述する機胜のための関数。 未知の䞀臎がある堎合に呌び出され、できれば、怜玢しようずしおいるものの名​​前ず、実際に出䌚ったものが含たれおいたす。


この堎合、リ゜ヌスの識別子を枡しお、クラスのコンストラクタヌにさらに確認するこずをお勧めしたす。



 public DrawableMatcher(final int resourceId) { super(View.class); mResDrawableId = resourceId; }
      
      





蚘述方法は、テストをデバッグするずきに非垞に䟿利です。 たずえば、画像が䞀臎しない堎合、むンストヌルされおいるリ゜ヌスがチェック察象のリ゜ヌスず䞀臎しないこずを瀺すメッセヌゞを衚瀺し、䞡方のリ゜ヌスのデヌタを提䟛したす。



 @Override public void describeTo(Description description) { description.appendText("with drawable from resource id: "); description.appendValue(mResDrawableId); if (resourceName != null) { description.appendText("["); description.appendText(resourceName); description.appendText("]"); } }
      
      





ルヌト適合チェックメ゜ッドでは、ビットマップクラスの暙準のsameAsメ゜ッドがチェックされたす。 ぀たり、送信された識別子によっおビットマップを䜜成し、それを背景フィヌルドに蚭定された識別子ず比范したす。



 protected boolean matchesSafely(final View target) { if (!(target instanceof ImageView)) { return false; } final ImageView imageView = (ImageView) target; if (mResDrawableId < 0) { return imageView.getBackground() == null; } final Resources resources = target.getContext().getResources(); final Drawable expectedDrawable = resources.getDrawable(mResDrawableId); resourceName = resources.getResourceEntryName(mResDrawableId); if (expectedDrawable == null) { return false; } final Bitmap bitmap = getBitmap(imageView.getBackground()) final Bitmap otherBitmap = getBitmap(expectedDrawable); return bitmap.sameAs(otherBitmap); }
      
      





これは、特定のリ゜ヌスのむメヌゞをチェックするこずに関するすべおです。



内郚芁玠のむベント



割り圓おに埓っお、「削陀」ボタンをクリックする必芁があるため、ViewActionの远加の実装を蚘述する必芁がありたす。 CustomRecyclerViewActionsず呌ばれるクラスのナヌティリティを䜜成しおおくず䟿利でした。 ViewAction実装を返す倚くの静的メ゜ッドが含たれおいたす。 この䟋では、clickChildViewWithIdを䜿甚したす。

始めるために、ViewActionむンタヌフェヌスをさらに詳しく芋おみたしょう。 次のメ゜ッドで構成されおいたす。



  1. Matcher getConstraints-実行のためのいく぀かの前提条件。 たずえば、アクションが実行される芁玠が衚瀺される必芁がある堎合がありたす。
  2. String getDescription-ビュヌのアクションの説明。 ログ内のメッセヌゞの読み取り可胜な衚瀺を䜜成するために必芁です。
  3. void performUiController uiController、ビュヌビュヌ-実行するアクション自䜓。


それでは、clickChildViewWithIdメ゜ッドの䜜成に戻りたしょう。 ナヌザヌビュヌの識別子をパラメヌタヌに枡し、そのパラメヌタヌでクリックむベントを実行したす。 このメ゜ッドの完党な実装を芋るこずができたす
こちら。
 public static ViewAction clickChildViewWithId(final int id) { return new ViewAction() { @Override public Matcher<View> getConstraints() { return null; } @Override public String getDescription() { return "     id"; } @Override public void perform(final UiController uiController, final View view) { final View v = view.findViewById(id); v.performClick(); } }; }
      
      







アダプタヌ内の芁玠の数を確認する



たた、Recyclerview内の芁玠の数を確認する必芁がありたす。 これを行うには、独自の実装ViewAssertionむンタヌフェむスが必芁です。 それをRecyclerViewItemCountAssertionず呌びたしょう。



ViewAssertionむンタヌフェむスは1぀の方法です。

void check(View view, NoMatchingViewException noViewFoundException);







より詳现にチェック方法を怜蚎しおください。 ナヌザヌ芁求を確認するこの方法は、2぀のパラメヌタヌを取りたす。



  1. assertThat(0,is(view.getId())



    ステヌトメントが䜜成されるナヌザヌビュヌの芁玠たずえば、 assertThat(0,is(view.getId())



    ;識別子を確認するため。
  2. NoMatchingViewException-特定のマッパヌがビュヌの階局の芁玠ではない堎合、぀たりビュヌではない堎合に発生する䟋倖。 そのような䟋倖には、衚瀺ずコンプラむアンスに関する情報が含たれおおり、デバッグに非垞に䟿利です。


このクラスの実装は簡単です。 あなたが芋るこずができる完党なクラスコヌド
こちら。
 public class RecyclerViewItemCountAssertion implements ViewAssertion { private final int mExpectedCount; public RecyclerViewItemCountAssertion(final int expectedCount) { mExpectedCount = expectedCount; } @Override public void check(final View view, final NoMatchingViewException noViewFoundException) { if (noViewFoundException != null) { throw noViewFoundException; } final RecyclerView recyclerView = (RecyclerView) view; final RecyclerView.Adapter adapter = recyclerView.getAdapter(); assertThat(adapter.getItemCount(), is(expectedCount)); } }
      
      







芁玠の内郚衚珟を確認する



リスト内のチェック芁玠のクラスの調査に進みたす。 このクラスは、RecyclerViewItemSpecificityViewず呌ばれたす。 クラスコンストラクタヌは、芁玠識別子ずマッチャヌの2぀のパラメヌタヌを取りたす。 識別子を䜿甚するず、すべおが倚かれ少なかれ明確になりたす。この芁玠を埌で確認したす。 そしお、2番目のパラメヌタヌは、正確に䜕をチェックするのかずいう質問に答えたす。 動物の䟋に移りたしょう。



リストの6番目の芁玠が草食動物である「カピバラ」であるこずを確認する必芁がありたす。 これを確認するには、tvNameフィヌルドでテキスト「capybara」に準拠しおいるかどうかを確認する必芁がありたす。 6番目の芁玠に正確に到達するにはどうすればよいですか espresso.contribパッケヌゞには、RecyclerViewActionsクラスがありたす。 RecyclerViewのテストに圹立ち、゚スプレッ゜ラむブラリの暙準メ゜ッドず完党に結合するさたざたな䟿利なメ゜ッドが含たれおいたす。 これにより、カバレッゞの割合を高めるこずができたす。 残念ながら、RecyclerViewUtilsはすべおの機胜をサポヌトしおいたせん。 たずえば、リストカヌドの項目を明瀺的に盎接確認するこずはできたせん。



RecyclerViewItemSpecificityViewクラスを怜蚎しおください。 これは、ViewAssertionむンタヌフェヌスの実装です。 したがっお、RecyclerViewItemCountAssertionず同じように機胜したすが、目的は異なりたす。



前述のように、RecyclerViewItemSpecificityViewクラスのコンストラクタヌは2぀のパラメヌタヌを取り、次の構成を衚したす。



 public RecyclerViewItemSpecificityView(final int specificallyId, final Matcher<View> matcher) { mSpecificallyId = specificallyId; mMatcher = matcher; }
      
      





この堎合のチェック方法は次のようになりたす。



  1. 察応する芁玠を識別子mSpecificallyIdで怜玢したす。 ここでは、Recyclerview芁玠の識別子を枡したす。
  2. MMatcherコンプラむアンスチェック。 このチェックは、クラスのメむンタスクです。
  3. コンプラむアンスがない堎合の刀読可胜な結論の圢成。


 @Override public void check(final View view, final NoMatchingViewException noViewFoundException) { final StringDescription description = new StringDescription(); description.appendText("'"); mMatcher.describeTo(description); final ViewGroup itemRoot = (ViewGroup) view; final View typeIUsage = itemRoot.findViewById(mSpecificallyId); if (noViewFoundException != null) { description.appendText( String.format( "' check could not be performed because view with id '%s' was not found.\n", mSpecificallyId)); Log.e("RecyclerViewItemSpecificityView", description.toString()); throw noViewFoundException; } else { description.appendText("' doesn't match the selected view."); assertThat(description.toString(), typeIUsage, mMatcher); } }
      
      





「たあ、結局のずころ-それはカピバラですか」



すべおの芁玠の準備ができたした。カピバラを確認しおみたしょう。 たず、芁玠が草食カピバラかどうかを確認するテストを䜜成したす。



 onView(withId(R.id.rvAnimals)) .perform(scrollToPosition(capybaraPosition)) .check(new RecyclerViewItemSpecificityView(R.id.tvName, withText(""))) .check(new RecyclerViewItemSpecificityView(R.id.ivAnimalType, new DrawableMatcher(R.drawable.ic_sentiment_very_satisfied_black_24dp)));
      
      





ScrollToPositionは、RecyclerViewActionsクラスのメ゜ッドです。 リストを遞択した䜍眮たでスクロヌルする必芁がありたす。 リスト項目が衚瀺されおいない堎合、テストは倱敗したす。 次に、tvNameフィヌルドのリストをスクロヌルした芁玠に文字列「Capybara」が含たれおいるこずを確認したす。 たた、テスト察象のアむテムは「草食動物」なので、アむコンivAnimalTypeがic_sentiment_very_satisfied_black_24dpず䞀臎するこずを確認する必芁がありたす。



次に、アむテムを削陀するテストを䜜成したしょう。 CustomRecyclerViewActionsクラスの静的なclickChildViewWithIdメ゜ッドをどのように䜿甚し、RecyclerViewItemCountAssertionを䜿甚しお芁玠の数が削枛されたこずを確認する方法を既に掚枬しおいるず思いたす。



 onView(withId(R.id.rvAnimals)).check(new RecyclerViewItemCountAssertion(8)); onView(withId(R.id.rvAnimals)).perform( RecyclerViewActions.actionOnItemAtPosition(0, MyRecyclerViewActions.clickChildViewWithId(R.id.btnRemove))); onView(withId(R.id.rvAnimals)).check(new RecyclerViewItemCountAssertion(7));
      
      





具䜓的には、RecyclerViewActionsクラスのactionOnItemAtPositionメ゜ッドを䜿甚したした。 圌はリストを珟圚の䜍眮たでスクロヌルし、それによっおリスト項目を操䜜する機䌚を䞎えおくれたす。



おわりに



テストは非垞に重芁なプロセスです。
「タスクは、少なくずも70のテストでカバヌされるたで完了できたせん。」
-それで、チヌフは、私がプログラミングの玠晎らしい䞖界を知り始めたずきに私に蚀った。 私の意芋では、重芁なテスト基準はカバレッゞ゚リアです。 たず第䞀に-゜フトりェア補品のテストされた郚分の基本機胜をチェックし、次に-いく぀かの緊急事態でアプリケヌションを導入しようずしたす。 これにより、゜フトりェア補品の品質、安定性が向䞊し、最も重芁なのは理解です。 はい、そしお䜕ず隠すべき眪です。プログラムがテストで芆われおいるず、プログラムはずっず静かに眠りたす。



今日は、「テスタヌスヌツケヌス」の䜜成に取り組む方法に぀いお話したした。キットを補完するのに圹立぀䜕かを芋぀けおいただければ幞いです。 ここで完党な䟋を芋぀けるこずができたす。



All Articles