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


103

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

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

답변:


125

저를 올바른 방향으로 안내 해준 @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"))
));

49

시험:

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

2
사이드 노드처럼-이것은 햄 크레스트 솔루션입니다 (assertj가 아님)
Hartmut P.

46

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

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

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

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


2
약간의 개선 :.. assertTrue (myClass.getMyItems () 스트림 () anyMatch (항목 -> "foo는".equals (item.getName ()));
로드리고 Manyari

@RodrigoManyari는, 닫는 괄호가 누락
Abdull

1
이 솔루션은 적절한 오류 메시지를 표시 할 가능성을 낭비합니다.
Giulio Caccin

@GiulioCaccin 나는 그렇게 생각하지 않는다. JUnit을 사용하는 경우 오버로드 된 assertion 메서드를 사용하고 assertTrue (..., "My own test failure message")를 작성할 수 있습니다. junit.org/junit5/docs/current/api/org/junit/jupiter/api/…
Mario Eis

부울에 대해 어설 션을 수행하면 실제 / 예상 차이를 자동으로 인쇄하는 기능을 잃게됩니다. 매처를 사용하여 어설 션 할 수 있지만이를 수행하려면이 페이지의 다른 응답과 유사하도록이 응답을 수정해야합니다.
Giulio Caccin

20

Assertj 는 이것을 잘합니다.

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

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

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


16

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")
           ); 

4
이것이 왜 찬성 투표가 없는지 이해하지 마십시오. 지금까지 이것이 최선의 답이라고 생각합니다.
PeMa

1
assertJ 라이브러리는 JUnit assertion API보다 훨씬 더 읽기 쉽습니다.
Sangimed dec

@Sangimed Agreed와 나는 햄 크레스트보다 선호합니다.
davidxxx 18:49에

제 생각에 이것은 "예상 값"에서 "실제 값"을 분리하여 일치해야하는 순서로 배치하기 때문에 약간 읽기 어렵습니다.
Terran

5

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")));

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


1
나는 당신의 솔루션을 정말 좋아하지만 테스트를 위해 모든 코드를 수정해야합니까?
Kevin Bowersox 2012 년

여기에있는 모든 답변에는 테스트 설정, 테스트 할 메서드 실행 및 속성 주장이 필요하다고 생각합니다. 내가 볼 수있는 것에서 내 대답에 대한 실제 오버 헤드는 없습니다. 단지 나는 seaprate 라인에 두 개의 주장을 가지고있어서 실패한 주장이 어떤 값이 누락되었는지 명확하게 식별 할 수 있다는 것입니다.
Brad

오류 메시지를 더 잘 이해할 수 있도록 assertTrue 내에 메시지를 포함하는 것이 가장 좋습니다. 메시지가 없으면 실패하면 JUnit은 오류 메시지없이 AssertionFailedError를 발생시킵니다. 따라서 "results should contain new MyItem (\"foo \ ")"과 같은 것을 포함하는 것이 가장 좋습니다.
Max

네, 맞아요. 어쨌든 Hamcrest를 추천하고 싶습니다. 요즘 assertTrue ()를 사용하지 않습니다
Brad

보조 노트에 POJO 또는 DTO는 equals 메소드 정의해야합니다
Tayab 후세인

1

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

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

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

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.