[java] Iterable에 특정 속성을 가진 요소가 포함되어 있다고 어떻게 주장합니까?

이 서명으로 메서드를 단위 테스트하고 싶다고 가정합니다.

List<MyItem> getMyItems();

MyItem많은 속성이있는 Pojo라고 가정합니다. 그 중 하나는를 "name"통해 액세스됩니다 getName().

내가 확인하는 데 관심이있는 것은 List<MyItem>, 또는 any Iterable에 속성 값이 and MyItem인 두 개의 인스턴스 가 포함되어 "name"있다는 것 입니다. 다른 속성이 일치하지 않는 경우이 테스트의 목적에 신경 쓰지 않습니다. 이름이 일치하면 성공적인 테스트입니다."foo""bar"

가능한 한 한 줄로하고 싶습니다. 여기 제가하고 싶은 “의사 구문”이 있습니다.

assert(listEntriesMatchInAnyOrder(myClass.getMyItems(), property("name"), new String[]{"foo", "bar"});

Hamcrest가 이런 유형에 적합할까요? 그렇다면 위의 의사 구문의 햄 크레스트 버전은 정확히 무엇입니까?



답변

저를 올바른 방향으로 안내 해준 @Razvan에게 감사드립니다. 나는 그것을 한 줄로 얻을 수 있었고 Hamcrest 1.3의 수입품을 성공적으로 추적했습니다.

수입품 :

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.beans.HasPropertyWithValue.hasProperty;

코드:

assertThat( myClass.getMyItems(), contains(
    hasProperty("name", is("foo")), 
    hasProperty("name", is("bar"))
));


답변

시험:

assertThat(myClass.getMyItems(),
                          hasItem(hasProperty("YourProperty", is("YourValue"))));


답변

특히 Hamcrest는 아니지만 여기서 언급 할 가치가 있다고 생각합니다. Java8에서 자주 사용하는 것은 다음과 같습니다.

assertTrue(myClass.getMyItems().stream().anyMatch(item -> "foo".equals(item.getName())));

(Rodrigo Manyari의 약간의 개선을 위해 편집되었습니다. 약간 덜 장황합니다. 주석을 참조하십시오.)

읽기가 조금 더 어려울 수 있지만 유형 및 리팩토링 안전성이 마음에 듭니다. 또한 여러 빈 속성을 조합하여 테스트하는 데 유용합니다. 예를 들어 필터 람다에서 자바와 유사한 && 표현식을 사용합니다.


답변

Assertj 는 이것을 잘합니다.

import static org.assertj.core.api.Assertions.assertThat;

    assertThat(myClass.getMyItems()).extracting("name").contains("foo", "bar");

hamcrest에 비해 assertj의 큰 장점은 코드 완성을 쉽게 사용할 수 있다는 것입니다.


답변

AssertJ는 다음과 같은 뛰어난 기능을 제공 합니다. s를 extracting()전달 Function하여 필드를 추출 할 수 있습니다. 컴파일 타임에 검사를 제공합니다.
먼저 크기를 쉽게 주장 할 수도 있습니다.

그것은 줄 것입니다 :

import static org.assertj.core.api.Assertions;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName)
          .containsExactlyInAnyOrder("foo", "bar"); 

containsExactlyInAnyOrder() 순서에 관계없이 목록에 이러한 값만 포함되어 있다고 주장합니다.

목록에 순서에 관계없이 이러한 값이 포함되지만 다른 값도 포함될 수 있다고 주장하려면 다음을 사용하십시오 contains().

.contains("foo", "bar"); 

참고로 :의 요소에서 여러 필드를 주장하려면 ListAssertJ를 사용하여 각 요소에 대한 예상 값을 tuple()함수 로 래핑하여 수행합니다.

import static org.assertj.core.api.Assertions;
import static org.assertj.core.groups.Tuple;

Assertions.assertThat(myClass.getMyItems())
          .hasSize(2)
          .extracting(MyItem::getName, MyItem::getOtherValue)
          .containsExactlyInAnyOrder(
               tuple("foo", "OtherValueFoo"),
               tuple("bar", "OtherValueBar")
           ); 


답변

List가 구체적인 클래스 인 한 MyItem에 equals () 메서드를 구현 한 경우 contains () 메서드를 간단히 호출 할 수 있습니다.

// given 
// some input ... you to complete

// when
List<MyItems> results = service.getMyItems();

// then
assertTrue(results.contains(new MyItem("foo")));
assertTrue(results.contains(new MyItem("bar")));

주장하려는 값을 허용하는 생성자를 구현했다고 가정합니다. 나는 이것이 한 줄에 있지 않다는 것을 알고 있지만 한 번에 두 가지를 모두 확인하는 것보다 어떤 값이 누락되었는지 아는 것이 유용합니다.


답변

AssertJ 3.9.1은 anyMatch메서드 에서 직접 술어 사용을 지원합니다 .

assertThat(collection).anyMatch(element -> element.someProperty.satisfiesSomeCondition())

이것은 임의로 복잡한 조건에 일반적으로 적합한 사용 사례입니다.

간단한 조건의 경우 extracting테스트 중 반복 가능한 결과가 더 나은 가독성으로 값 확인을 지원할 수 있기 때문에 메서드 (위 참조)를 사용하는 것을 선호합니다 . 예 : containsFrank Neblung의 답변에서 메소드 와 같은 특수 API를 제공 할 수 있습니다 . 또는 anyMatch나중에 어쨌든 호출 하고 "searchedvalue"::equals. 또한 여러 추출기를 extracting메서드에 넣을 수 있으며 결과는 tuple().