이 서명으로 메서드를 단위 테스트하고 싶다고 가정합니다.
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");
참고로 :의 요소에서 여러 필드를 주장하려면 List
AssertJ를 사용하여 각 요소에 대한 예상 값을 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
테스트 중 반복 가능한 결과가 더 나은 가독성으로 값 확인을 지원할 수 있기 때문에 메서드 (위 참조)를 사용하는 것을 선호합니다 . 예 : contains
Frank Neblung의 답변에서 메소드 와 같은 특수 API를 제공 할 수 있습니다 . 또는 anyMatch
나중에 어쨌든 호출 하고 "searchedvalue"::equals
. 또한 여러 추출기를 extracting
메서드에 넣을 수 있으며 결과는 tuple()
.