2016-01-26 4 views
1

Я пытаюсь использовать сопоставления hamcrest для сопоставления списка объектов со списком/массивом их свойств. Для одного значения свойства это не проблема, потому что я могу сделать что-то вроде этого:Матч Список объектов со списком свойств

assertThat(savedGroup.getMembers(), 
    containsInAnyOrder(hasProperty("name", is(NAMES[0])))); 

Для нескольких значений свойств можно использовать несколько HasProperty() вызывает

assertThat(savedGroup.getMembers(), 
    containsInAnyOrder(
     hasProperty("name", is(NAMES[0])), 
     hasProperty("name", is(NAMES[1])))); 

Но есть универсальный способ чтобы совместить все значения в массиве NAMES?

ответ

3

Лучший способ (ИМО), чтобы сделать это было бы объединить перегруженный containsInAnyOrder Искателя вместе с обычаем FeatureMatcher. В конечном счете ваш код будет выглядеть следующим образом:

String[] expectedNames = new String[] { "John", "Bob", "Carol"}; 
assertThat(savedGroup.getMembers(), hasNames(expectedNames)); 

hasNames реализуется следующим образом:

private Matcher<Iterable<? extends Member>> hasNames(String[] expectedNames) { 
    return containsInAnyOrder(Arrays.stream(expectedNames).map(name -> name(name)).collect(Collectors.toList())); 
} 

И заключительная часть вызова name, который генерирует Искатель, который будет извлекать недвижимость в типа- безопасный путь от вашего объекта:

private Matcher<Member> name(String name) { 
    return new FeatureMatcher<Member, String>(equalTo(name), "name", "name") { 
     @Override 
     protected String featureValueOf(Member actual) { 
      return actual.getName(); 
     } 
    }; 
} 

преимущество делать это, это способ заключается в следующем:

  • Вы получаете преимущество безопасности типов вместо использования hasProperty
  • Вашего теста описывает то, что вы хотите, чтобы фактический матч на, т.е. hasNames
  • Код производится теперь более гибкий и компонуем. Хотите совместить имя одного объекта? Все, что вам теперь нужно сделать, это assertThat(member, has(name("Fred")))

Вы можете получить еще больше компонуемости, перемещая equalTo суб-Искателя быть частью hasNames называют так:

private Matcher<Iterable<? extends Member>> hasNames(String[] expectedNames) { 
    return containsInAnyOrder(Arrays.stream(expectedNames).map(name -> name(equalTo(name))).collect(Collectors.toList())); 
} 

private Matcher<Member> name(Matcher<String> nameMatcher) { 
    return new FeatureMatcher<Member, String>(nameMatcher, "name", "name") { 
     @Override 
     protected String featureValueOf(Member actual) { 
      return actual.getName(); 
     } 
    }; 
} 
1

В одной из перегрузок containsInAnyOrder в качестве аргумента используется набор соответствий. Таким образом, вы могли бы сделать что-то вроде этого:

assertThat(
    savedGroup.getMembers(), 
    containsInAnyOrder(
     Stream.of(NAMES) 
       .map(name -> hasProperty("name", is(name))) 
       .collect(Collectors.toList()) 
    )); 

(при использовании Java 8, в противном случае нужно добавить цикл создания коллекции)

0

нужно сделать некоторые очистки (описание выход), но я думаю, это решить вашу проблему:

package org.example.matchers; 

import java.util.List; 

import org.hamcrest.Description; 
import org.hamcrest.Factory; 
import org.hamcrest.TypeSafeMatcher; 

public class ContainsArrayElementsInAnyOrder<T> extends TypeSafeMatcher<List<T>> { 

    private T[] toMatch; 

    public ContainsArrayElementsInAnyOrder(final T[] toMatch) { 
     this.toMatch = toMatch; 
    } 

    @Override 
    protected boolean matchesSafely(List<T> item) { 
     if(item.size() != toMatch.length) { 
      return false; 
     } 
     for (T t : toMatch) { 
      if(!item.contains(t)) { 
       return false; 
      } 
     } 
     return true; 
    } 

    @Override 
    public void describeMismatchSafely(List<T> item, Description mismatchDescription) { 
     mismatchDescription.appendValueList("[", ",", "]", item); 
    } 

    @Override 
    public void describeTo(Description description) { 
     description.appendValueList("[", ",", "]", toMatch); 
    } 

    @Factory 
    public static <T> ContainsArrayElementsInAnyOrder<T> containsArrayElementsInAnyOrder(T[] elements) { 
     return new ContainsArrayElementsInAnyOrder<T>(elements); 
    }  


} 

Тест:

@Test 
public void shouldContainsInAnyOrderSameElementsInArrayAsInList() { 
    final String[] NAME = new String[]{"name3", "name1", "name2"}; 

    final List<String> result = new ArrayList<>(3); 
    result.add("name2"); 
    result.add("name1"); 
    result.add("name4"); 

    assertThat(result, containsArrayElementsInAnyOrder(NAME)); 
} 

выход, если не матом ч:

java.lang.AssertionError: 
Expected: ["name3","name1","name2"] 
    but: ["name2","name1","name4"] 
    at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20) 
    at org.junit.Assert.assertThat(Assert.java:956) 
    at org.junit.Assert.assertThat(Assert.java:923) 
    at .. 

 Смежные вопросы

  • Нет связанных вопросов^_^