Java: How can I define an anonymous Hamcrest Matcher? - java

I'm trying use JUnit / Hamcrest to assert that a collection contains at least one element that my custom logic asserts is true. I'm hoping there's some kind of Matcher like 'anyOf' that takes a lambda (or anonymous class definition) where I can define the custom logic. I've tried TypeSafeMatcher but can't figure out what to do with it.
I don't think that anyOf is what I'm looking for either as that seem to take a list of Matchers.

what are you testing? There's a good chance you could use a combination of matchers like hasItem, allOf and hasProperty, otherwise you could implement org.hamcrest.TypeSafeMatcher. I find looking at the source code of existing matchers helps. I've created a basic custom matcher below that matches on a property
public static class Foo {
private int id;
public Foo(int id) {
this.id = id;
}
public int getId() {
return id;
}
}
#Test
public void customMatcher() {
Collection<Foo> foos = Arrays.asList(new Foo[]{new Foo(1), new Foo(2)});
assertThat(foos, hasItem(hasId(1)));
assertThat(foos, hasItem(hasId(2)));
assertThat(foos, not(hasItem(hasId(3))));
}
public static Matcher<Foo> hasId(final int expectedId) {
return new TypeSafeMatcher<Foo>() {
#Override
protected void describeMismatchSafely(Foo foo, Description description) {
description.appendText("was ").appendValue(foo.getId());
}
#Override
public void describeTo(Description description) {
description.appendText("Foo with id ").appendValue(expectedId);
}
#Override
protected boolean matchesSafely(Foo foo) {
// Your custom matching logic goes here
return foo.getId() == expectedId;
}
};
}

Perhaps Matchers.hasItems() can help you?
List<String> strings = Arrays.asList("a", "bb", "ccc");
assertThat(strings, Matchers.hasItems("a"));
assertThat(strings, Matchers.hasItems("a", "bb"));
Matchers also have a method for providing other Matcher as arguments, i.e. hasItems(Matcher<? super >... itemMatchers).
Moreover, there are some methods working on arrays hasItemInArray(T element) and hasItemInArray(Matcher<? super > elementMatcher)

Related

In Java, can I make a predicate that applies a filter on more than one object?

I have a predicate that I use to filter a list of the same Entity Object:
Predicate<DWHDeal> companyFilter = i -> i.getCompany().equals(company);
I also have to apply the same filter, with the exact same condition on the exact same field, on a list of DTOs where the DTOS is built based on the entity from before:
Predicate<DWHDealDTO> companyFilterDTO = i -> i.getCompany().equals(company);
Is it possible to achieve this without instancing two different predicates? If possible, I would like to achieve this by making only one Predicate.
Assuming getCompany() returns a String you could create Predicate<String>:
Predicate<String> predicate = s -> s.equals(company);
And then using it like:
list.stream()
.filter(dto -> predicate.test(dto.getCompany()))
...
But there is not much benefit since it requires almost the same code.
If equality is only check then you can use static Predicate isEqual(Object targetRef). see java doc https://docs.oracle.com/javase/8/docs/api/java/util/function/Predicate.html#isEqual-java.lang.Object-
class StudentView{
String name;
public StudentView(String name) {
this.name = name;
}
}
class StudentDTO{
String name;
public StudentDTO(String name) {
this.name = name;
}
}
public void testPredicate(){
StudentView studentView= new StudentView("John");
StudentDTO studentDTO = new StudentDTO("Sam");
Predicate p = Predicate.isEqual("John");
System.out.println("Test for Student View "+ p.test(studentView.name));
System.out.println("Test for Student DTO "+ p.test(studentDTO.name));
}
I think you will need a Function<T,R> before using Predicate :
There are two concepts to Function. First is a java.util.function.Function which accepts one argument and produces a result. The second is stream intermediate operation map which converts each element in a stream into another object via the supplied function.
In your case the Function should look like :
Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
public DWHDealDTO apply(DWHDeal t) {
return ... ;
}
};
I tried the basic Program as below with success:
static class DWHDeal{
String name;
public DWHDeal(String name) {
this.name = name;
}
}
static class DWHDealDTO{
String name;
public DWHDealDTO(String name) {
this.name = name;
}
}
static Predicate<DWHDealDTO> companyFilter = i -> i.name.equalsIgnoreCase("com");
public static void main(String[] args) {
Function<DWHDeal, DWHDealDTO> myFunction = new Function<DWHDeal, DWHDealDTO>() {
public DWHDealDTO apply(DWHDeal t) {
return new DWHDealDTO("com");
}
};
DWHDeal newDWHDealDTOObj = new DWHDeal("com");
System.out.println(companyFilter.test(myFunction.apply(newDWHDealDTOObj))); //Works
}
As suggested in the comments, the common interface would be the preferred solution.
I guess you could do something like this, but to be fair, it is ugly.
private String getCompany(Object o) {
if(o instanceof DWHDeal)
return ((DWHDeal) o).getCompany();
else
return ((DWHDealDTO) o).getCompany();
}
Predicate<Object> companyFilter = i -> getCompany(i).equals(company);

How to compare lists of custom classes without defining equals() and hashCode()?

Since defining equals() and hashCode() only for testing purpose is considered as a code smell, I prefer to use ReflectionEquals or custom matchers to compare objects while doing unit testing.
However, I don't know how to use ReflectionEquals or custom matchers in comparing lists of user-defined classes.
For example, how do I assert the following code without defining equals() and hashCode() (maybe only use ReflectionEquals or custom matchers)?
// When
List<Record> actual = sut.findBySomeId();
// Then
List<Record> expected = asList(
aRecord()...build(),
aRecord()...build()
);
assertThat(expected, /* how to compare? */);
There is a super fluent library for solving your issue, called AssertJ. It is quite easy to use, flexible to make changes and its fluency makes the tests easy to read!
In order to use it, first you have to import the right package
import static org.assertj.core.api.Assertions.*;
I do not know how your Record model looks like, so I made a dummy one:
public class Record {
private String name;
private String data;
private String history;
public Record(String name, String data, String history) {
this.name = name;
this.data = data;
this.history = history;
}
public String getName() {
return name;
}
public String getData() {
return data;
}
public String getHistory() {
return history;
}
}
Then the test would like like, if you only want to assert list of Record based on one field:
#Test
public void give_when_then() throws Exception {
List<Record> actualList = sut.findBySomeId();
assertThat(actualList)
.extracting(record -> record.getData())
.containsExactly("data1", "data2", "data3");
}
If you want to assert the objects based on multiple fields, you can do for example:
#Test
public void give_when_then() throws Exception {
List<Record> actualList = sut.findBySomeId();
assertThat(actualList)
.extracting(
record -> record.getName(),
record -> record.getHistory())
.containsExactly(
tuple("name1", "history1"),
tuple("name2", "history2"),
tuple("name3", "history3"));
}
...where tuple is also an assert4J object for wrapping the results.
Furthermore there are bunch of assert methods like containsExactlyInAnyOrder(...), containsAll(...), containsAnyOf(...) etc., which could also help your life in certain cases.
Last but not least you can also write your own specific object assert class extending AbstractObjectAssert base class. With this you will have (among others) a method called isEqualToComparingFieldByField. From the official documentation:
Assert that actual object is equal to the given object based on a property/field by property/field comparison (including inherited ones). This can be handy if equals implementation of objects to compare does not suit you.
First you define your own assert class:
public class RecordAssert extends AbstractObjectAssert<RecordAssert, Record> {
public RecordAssert(Record actual) {
super(actual, RecordAssert.class);
}
}
Then the usage of it would look like:
#Test
public void give_when_then() throws Exception {
List<Record> actual = sut.findBySomeId();
assertThat(actual.get(0)).isEqualToComparingFieldByField(new Record("name1", "data1", "history1"));
// Asserts for other objects
}
I hope it helps!
The Hamcrest library has a great selection of matchers for making assertions on collections types. In particular, the hasItem, hasItems, contains and containsAnyOrder matchers as these can use matchers themselves (I like to use TypeSafeMatcher) to test the items in the collections.
I'll leave you to decide which one best suits your needs, but I'll use contains for my example:
List<Record> actual = sut.findBySomeId();
Record expected1 = aRecord()...build();
Record expected2 = aRecord()...build();
assertThat(actual, contains(matchingRecord(expected1), matchingRecord(expected2));
...
// somewhere the test has access to it
private Matcher<Record> matchingRecord(Record expected) {
return new TypeSafeMatcher<Record>() {
public boolean matchesSafely(Record actual) {
// perform tests and return result, e.g.
return actual.getValue() == expected.getValue();
}
public void describeMismatchSafely(Record record, Description mismatchDescription) {
mismatchDescription.appendText("give a meaningful message");
}
};
}
I would say that using Reflection for checking equals/hashCode is another code smell in itself.
With Matcher, you must do something like that (I used the fully qualified name for clarity, use import instead): this will check that the value of result is the same as the one from expected. You can add as much field as you need.
assertThat(result, new org.hamcrest.BaseMatcher<MyObject>() {
public boolean matches(MyObject o) {
return java.lang.Objects.equals(o.getValue(), expected.getValue());
}
});
If you don't want to create a getter for the field of your class, then use default visibility (that what's does Guava and they annotate such fields with #VisibleForTesting).
You might also take a look at AssertJ to create custom and fluent matchers (it works more or less the same).
I have also faced this issue in the past and I am totally agree with you that implementing the equals() and hashCode() for only testing purpose is a code smell. I do not use Hamcrest library so I will provide you a custom solution which I successfully use in my projects and as for its usage I am quite pleased with it.
public static <E, A> void assertListEquals(BiConsumer<E, A> asserter, List<E> expected, List<A> actual) throws AssertionError {
assertEquals(
"Lists have different sizes. Expected list: " + expected + ", actual list: " + actual,
expected.size(),
actual.size());
for (int i = 0; i < expected.size(); i++) {
try {
asserter.accept(expected.get(i), actual.get(i));
} catch (AssertionError e) {
throw e;
}
}
}
As you can see, a BiConsumer is used in order to apply the logic for checking the equality of two objects. So this one has to be implemented in the test class. The advantage of it is that you can define the fields of a class you are interested in when comparing two objects.
Lets see the usage of it:
First we have a custom class, f.e.: Person
public class Person {
private String firstName;
private String lastName;
private int age;
public Person(String firstName, String lastName, int age) {
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int getAge() {
return age;
}
}
Then lets see a test method:
#Test
public void peopleLiveInTheVillage_findPeople_peopleAreFound() throws Exception {
//Arrange
List<Person> expectedPeople = Arrays.asList(
new Person("Lewis", "Smith", 20),
new Person("Steven", "Richard", 25),
new Person("Richie", "Rich", 30));
//Act
List<Person> actualPeople = sut.findPeople();
//Assert
assertListEquals(
(e, a) -> assertPersonEquals(e, a),
expectedPeople,
actualPeople);
}
private void assertPersonEquals(Person expected, Person actual) {
assertEquals(expected.getFirstName(), actual.getFirstName());
assertEquals(expected.getLastName(), actual.getLastName());
assertEquals(expected.getAge(), actual.getAge());
}
Since I am a big fan of tests (and TDD) I always write tons of tests so I always make a helper method where I wrap the BiConsumer:
private void assertPeopleEqual(List<Person> expectedPeople, List<Person> actualPeople) throws AssertionError {
assertListEquals(
(e, a) -> assertPersonEqual(e, a),
expectedPeople,
actualPeople);
}
I hope this helps, cheers!

Match List of objects against list of properties

I'm trying to use hamcrest matchers to match a list of objects against a list/array of their properties. For one property value this is not a problem, because I can do something like this:
assertThat(savedGroup.getMembers(),
containsInAnyOrder(hasProperty("name", is(NAMES[0]))));
For multiple property values I can use multiple hasProperty() calls
assertThat(savedGroup.getMembers(),
containsInAnyOrder(
hasProperty("name", is(NAMES[0])),
hasProperty("name", is(NAMES[1]))));
But is there a generic way to match against all values in the NAMES array?
The best way (IMO) to do this would be to combine the overloaded containsInAnyOrder Matcher along with a custom FeatureMatcher. Ultimately your code would look like this:
String[] expectedNames = new String[] { "John", "Bob", "Carol"};
assertThat(savedGroup.getMembers(), hasNames(expectedNames));
hasNames is implemented as follows:
private Matcher<Iterable<? extends Member>> hasNames(String[] expectedNames) {
return containsInAnyOrder(Arrays.stream(expectedNames).map(name -> name(name)).collect(Collectors.toList()));
}
And the final part is the call to name which generates a Matcher that will extract a property in a type-safe way from your object:
private Matcher<Member> name(String name) {
return new FeatureMatcher<Member, String>(equalTo(name), "name", "name") {
#Override
protected String featureValueOf(Member actual) {
return actual.getName();
}
};
}
The benefit of doing it this is way is that:
You get the benefit of type-safety instead of using hasProperty
Your test now describes what you actual want to match on, i.e. hasNames
The code produced is now more flexible and composable. Want to match a single objects name? All you now need to do is assertThat(member, has(name("Fred")))
You can get even more composability by moving the equalTo sub-matcher to be part of the hasNames call like this:
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();
}
};
}
One of containsInAnyOrder's overloads accepts a collection of matchers as its argument. Thus you could do something like this:
assertThat(
savedGroup.getMembers(),
containsInAnyOrder(
Stream.of(NAMES)
.map(name -> hasProperty("name", is(name)))
.collect(Collectors.toList())
));
(if using Java 8, otherwise would need to add a loop building up the collection)
Need to make some cleanup (description output), but I think it does solve your problem:
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:
#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));
}
Output if not match:
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 ..

Looking for appropriate design pattern

Our code has several processors, each one having several api methods, where each method is overloaded also with same method that can accept collection.
For example:
public class Foo {
public X foo(Y y){...}
public Collection<X> foo(Collection<Y> y){... // iterate and execute foo(y) ... }
public Z bar(W w){...}
public Collection<Z> bar(Collection<W> w){... // iterate and execute bar(w) ... }
}
public class Other{
// also method and method on collection
}
Naturally, those methods on collections are actually duplication code of iteration.
What we are looking for, is kind of way to make some pattern or use generics, so the iteration over collection will be implemented once, also for that need a way to somehow pass the method name.
I'd suggest Startegy pattern. And do something like:
public interface Transformer<X, Y> {
Y transform( X input );
}
class Processor {
public <X,Y> Collection<Y> process( Collection<X> input, Transformer<X, Y> transformer) {
Collection<Y> ret = new LinkedList<Y>();
// generic loop, delegating transformation to specific transformer
for( X x : input) {
ret.add( transformer.transform( x ) );
}
return ret;
}
}
Example:
public static void main( String[] args ) {
List<String> strings = new LinkedList<String>();
strings.add( "1" );
strings.add( "2" );
strings.add( "3" );
Processor p = new Processor();
Collection<Integer> numbers = p.process( strings, new Transformer<String, Integer>() {
#Override
public Integer transform( String input ) {
return Integer.parseInt( input );
}
} );
}
I can't see how reflection could help here. You're trying to replace something as trivial as
public Collection<X> foo(Collection<Y> y) {
List<X> result = Lists.newArrayList();
for (Y e : y) result.add(foo(e));
return result;
}
by something probably much slower. I don't think that saving those 3 lines (several times) is worth it, but you might want to try either annotation processing (possibly without using annotations) or dynamic code generation. In both cases you'd write the original class as is without the collection methods and use a different one containing both the scalar and the collection methods.
Or you might want to make it more functionally styled:
public class Foo {
public final RichFunction<Y, X> foo = new RichFunction<Y, X>() {
X apply(Y y) {
return foo(y);
}
}
// after some refactoring the original method can be made private
// or inlined into the RichFunction
public X foo(Y y){...}
// instead of calling the original method like
// foo.foo(y)
// you'd use
// foo.foo.apply(y)
// which would work for both the scalar and collection methods
}
public abstract class RichFunction<K, V> extends com.google.common.base.Function<K, V> {
Collection<V> apply(Collection<K> keys) {
List<V> result = Lists.newArrayList();
for (K k : keys) result.add(apply(k));
return result;
}
}
RUAKH - I chosed to implement your suggestion for reflection (although, admit, I don't like reflection). So, I did something like the code below THANKS :)
public class Resource {
private static final int CLIENT_CODE_STACK_INDEX;
static {
// Finds out the index of "this code" in the returned stack trace - funny but it differs in JDK 1.5 and 1.6
int i = 0;
for (StackTraceElement ste : Thread.currentThread().getStackTrace()) {
i++;
if (ste.getClassName().equals(Resource.class.getName())) {
break;
}
}
CLIENT_CODE_STACK_INDEX = i;
}
public static String getCurrentMethodName() {
return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX].getMethodName();
}
protected <IN,OUT> Collection<OUT> doMultiple(String methodName, Collection<IN> inCol, Class<?>... parameterTypes){
Collection<OUT> result = new ArrayList<OUT>();
try {
Method m = this.getClass().getDeclaredMethod(methodName, parameterTypes);
if (inCol==null || inCol.size()==0){
return result;
}
for (IN in : inCol){
Object o = m.invoke(this, in);
result.add((OUT) o);
}
}catch (Exception e){
e.printStackTrace();
}
return result;
}
}
public class FirstResource extends Resource{
public String doSomeThing(Integer i){
// LOTS OF LOGIC
return i.toString();
}
public Collection<String> doSomeThing(Collection<Integer> ints){
return doMultiple(getCurrentMethodName(), ints, Integer.class);
}
}
You should use Strategy pattern. By using Strategy pattern you can omit the usage if/else which makes the code more complex. Where strategy pattern creates less coupled code which is much simpler. By using Strategy pattern you can achieve more ways to configure code dynamically. So I would like to suggest you to use Strategy pattern.

Is there a Union in Java Generics?

Can I contain two different types in a collection? For example, can I have List< String U Integer > ?
Short answer? No. You can (of course) have a List of Objects, but then you can put anything in it, not just String or Integer objects.
You could create a list of container objects, and that container object would contain either an Integer or String (perhaps via generics). A little more hassle.
public class Contained<T> {
T getContained();
}
and implement Contained<Integer> and Contained<String>.
Of course, the real question is why you want to do this? I would expect a collection to contain objects of the same type, and then I can iterate through and perform actions on these objects without worrying what they are. Perhaps your object hierarchy needs further thought?
Nope. You have a couple of alternatives, though:
You can use a List < Object > and stash whatever you like; or
You can use a List < Class-with-2-members > and put your data in one of those class members.
EDIT: Example.
class UnionHolder {
public String stringValue;
public int intValue;
}
List < UnionHolder > myList
...
Of course you'll need a bit of additional code to figure out which kind of data to pull out of the UnionHolder object you just got out of your list. One possibility would be to have a 3rd member which has different values depending on which it is, or you could, say, have a member function like
public boolean isItAString() { return (this.stringValue != null }
If you are doing something like functional programming in Java 8 or above, you may want to try JavaSealedUnions:
Union2.Factory<String, Integer> factory = GenericUnions.doubletFactory();
Union2<String, Integer> strElem = factory.first("hello");
Union2<String, Integer> intElem = factory.second(3);
List<Union2<String, Integer>> list = Array.asList(strElem, intElem);
for (Union2<String, Integer> elem : list) {
elem.continued(
strElem -> System.out.println("string: " + strElem),
intElem -> System.out.println("integer: " + intElem));
}
Haven't tested this, but I think you got the idea.
In addition to the nice answers already provided ...
Possibly, you have the two data types in your algorithm. But you may not have to put them in the same list...
Creating two typed lists could be the clearer for your algorithm, you would still keep the "type-safeness" and carry all your data. Two code samples follow, the second grouping the two lists in a MyData object.
public class Algorithm1 {
public void process(List<String> strings, List<Integer> integers) {
...
}
}
--------------------------------------
public class DataPair {
public List<String> strings;
public List<Integer> integers;
}
public class Algorithm2 {
public void process(DataPair dataPair) {
...
}
}
what you're decribing is the perfect use case for the Visitor pattern
100% statically type-checked
doesn't need Java 8 or above
usage:
List<UnionType> unionTypes = Arrays
.asList(new StringContainer("hello"), new IntegerContainer(4));
for (UnionType unionType : unionTypes) {
unionType.when(new UnionType.Cases<Integer>() {
#Override
public Integer is(StringContainer stringContainer) {
// type-specific handling code
}
#Override
public Integer is(IntegerContainer integerContainer) {
// type-specific handling code
}
});
}
boilerplate code:
interface UnionType {
<R> R when(Cases<R> c);
interface Cases<R> {
R is(StringContainer stringContainer);
R is(IntegerContainer integerContainer);
}
}
class StringContainer implements UnionType {
private final String value;
public StringContainer(String value) { this.value = value; }
public String getValue() { return value; }
#Override
public <R> R when(Cases<R> cases) {
return cases.is(this);
}
}
class IntegerContainer implements UnionType {
private final Integer value;
public IntegerContainer(Integer value) { this.value = value; }
public Integer getValue() { return value; }
#Override
public <R> R when(Cases<R> cases) {
return cases.is(this);
}
}
No. Think about it this way: with generics, the whole idea is to provide type safety. That would not be possible if you could put Objects of different types into it.
You can use the non-generic java.util.List for your purpose.
If you want to ensure that only String or Integer objects enter the list, you could create your own List implementation like so:
public class MySpecialList {
private List list= new LinkedList();
...
public void add(final String string) {
list.add(string);
}
public void add(final Integer integer) {
list.add(integer);
}
...
// add rest of List style methods
}
Drawback: you loose the List interface clarity...

Categories