web-dev-qa-db-ja.com

assertThat-hamcrest-リストがソートされているかどうかを確認します

わかりました、それは短い質問になると思います。日付でソートしたArrayListがあります。もちろん、それは機能するようですが、テストも作成したいと思います。

リストの次の値(日付)が前の値よりも低いかどうかを確認したいと思います。いくつかのforを使用し、一時リストを追加することでそれを行うことができますが、もっと簡単な解決策があるかどうか疑問に思っています。ハムレストのドキュメントを読んだところ、オブジェクト(リスト、マップなど)を反復処理するcontains(hamrest contains)のようなものがあると思いましたが、それでも次に何をすべきかわかりません。

17
lukaszrys

[最初のオプション]:独自のマッチャーを作成できます。次のようなもの(免責事項:これは単なるサンプルコードであり、テストされておらず、完全ではない可能性があります):

_@Test
  public void theArrayIsInDescendingOrder() throws Exception
  {
    List<Integer> orderedList = new ArrayList<Integer>();
    orderedList.add(10);
    orderedList.add(5);
    orderedList.add(1);
    assertThat(orderedList, isInDescendingOrdering());
  }

  private Matcher<? super List<Integer>> isInDescendingOrdering()
  {
    return new TypeSafeMatcher<List<Integer>>()
    {
      @Override
      public void describeTo (Description description)
      {
        description.appendText("describe the error has you like more");
      }

      @Override
      protected boolean matchesSafely (List<Integer> item)
      {
        for(int i = 0 ; i < item.size() -1; i++) {
          if(item.get(i) <= item.get(i+1)) return false;
        }
        return true;
      }
    };
  }
_

この例はIntegersを使用していますが、Datesを使用すると簡単に実行できます。

[2番目のオプション]、OPの質問のcontainsへの参照に基づく:assertThat(Origin, contains(ordered))を使用するよりも、元のリストを並べて2番目のリストを作成できます。このようにして、要素が予期された順序にない場合に指摘されるため、最終的なエラーがより正確に記述されます。たとえば、このコード

_@Test
  public void testName() throws Exception
  {
    List<Integer> actual = new ArrayList<Integer>();
    actual.add(1);
    actual.add(5);
    actual.add(3);
    List<Integer> expected = new ArrayList<Integer>(actual);
    Collections.sort(expected);
    assertThat(actual, contains(expected.toArray()));
  }
_

説明を生成します

_Java.lang.AssertionError: 
Expected: iterable containing [<1>, <3>, <5>]
     but: item 1: was <5>
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.Java:20)
    at org.junit.Assert.assertThat(Assert.Java:865)
    at org.junit.Assert.assertThat(Assert.Java:832)
    ...
_
18

そのようなマッチャーのオープンリクエスト がありますが、残念ながらまだ実装されていません。

私はもっ​​と簡単なものを探します-リストをコピーしてソートし、元のリストと比較します:

@Test
public void testListOrder() {
    ArrayList<SomeObject> original = ...;
    ArrayList<SomeObject> sorted = new ArrayList<SomeObject>(original);
    Collections.sort(sorted);
    Assert.assertEquals ("List is not sorted", sorted, original);
}

編集:
@ dsncodeはコメントに良い点があります-(比較的)エレガントですが、このソリューションはパフォーマンスを考慮して設計されていません。リストが大きすぎない場合は問題ありませんが、リストが大きい場合は、並べ替えにコストがかかる可能性があります。リストが大きい場合は、リストを直接繰り返して、前の要素よりも小さい要素に遭遇した場合はテストに失敗することをお勧めします。例えば。:

assertTrue(() -> {
    Iterator<SomeClass> iter = list.iterator();

    SomeClass prev = null;
    if (iter.hasNext()) {
        prev = iter.next();
    }

    SomeClass curr = null;
    while (iter.hasNext()) {
        curr = iter.next();
        if (curr.compareTo(prev) < 0) {
            return false;
        }
        prev = curr;
    }

    return true;
});
15
Mureinik

また、GUAVAを使用して確認することもできます。

import com.google.common.collect.Ordering;

.。

assertTrue(Ordering.natural().isOrdered(list));

詳細はこちら: リストがJavaでソートされているかどうかを確認する方法は?

10

小さなコレクションの場合、コードでハードコードされた期待されるコレクションを提供することをお勧めします。これは単体テストであり、ロジックを含めることはできません。その後、2つのコレクションを比較できます。 (hamcrestを使用して同等のものを確認してください)

3
Areo

同様の問題が発生しました。ミリ秒単位の次の日付値が、そのリストの前の日付値よりも大きい/小さいかどうかを確認するだけです。

/**
 * Test sort by date
 */
@Test
public void findAllMessagesSortByDate() {
    Collection<Message> messages = messageService.getAllMessagesSortedByDate();
    long previousTime = messages.iterator().next().getDate().getTimeInMillis();
    for (Message message : messages) {
        assertTrue(message.getDate.getTimeInMillis() <= previousTime);
        previousTime = message.getMessageFolderTs().getTimeInMillis();
    }
}
2
Zhenya

別のトピックで私の答えを確認できますが、アプローチは同じです。アイテムが期待どおりの順序であるかどうかを確認する必要があります。

Hamcrestを使用してコレクションに特定の順序でアイテムが含まれているかどうかを確認する方法

このアプローチでは、「Hamcrest」ライブラリが使用されることを想定しています。

お役に立てれば。

0
nndru