Why doesn't this code attempting to use Hamcrest's hasItems compile?

JavaUnit TestingJunitHamcrestMatcher

Java Problem Overview


Why does this not compile, oh, what to do?

import static org.junit.Assert.assertThat;
import static org.junit.matchers.JUnitMatchers.hasItems;

ArrayList<Integer> actual = new ArrayList<Integer>();
ArrayList<Integer> expected = new ArrayList<Integer>();
actual.add(1);
expected.add(2);
assertThat(actual, hasItems(expected));

error copied from comment:

cannot find symbol method assertThat(java.util.ArrayList<java.lang.Integer>, org.hamcreset.Matcher<java.lang.Iterable<java.util.ArrayList<java.lang.Integer>>>)

Java Solutions


Solution 1 - Java

Just ran into this post trying to fix it for myself. Gave me just enough information to work it out.

You can give the compiler just enough to persuade it to compile by casting the return value from hasItems to a (raw) Matcher, eg:

ArrayList<Integer> actual = new ArrayList<Integer>();
ArrayList<Integer> expected = new ArrayList<Integer>();
actual.add(1);
expected.add(2);
assertThat(actual, (Matcher) hasItems(expected));

Just in case anybody else is still suffering ...

Edit to add: In spite of the up votes, this answer is wrong, as Arend points out below. The correct answer is to turn the expected into an array of Integers, as hamcrest is expecting:

	ArrayList<Integer> actual = new ArrayList<Integer>();
	ArrayList<Integer> expected = new ArrayList<Integer>();
	actual.add(1);
	expected.add(2);
	assertThat(actual, hasItems(expected.toArray(new Integer[expected.size()])));

Solution 2 - Java

hasItems checks that a collection contains some items, not that 2 collections are equal, just use the normal equality assertions for that. So either assertEquals(a, b) or using assertThat

import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.is;

ArrayList<Integer> actual = new ArrayList<Integer>();
ArrayList<Integer> expected = new ArrayList<Integer>();
actual.add(1);
expected.add(2);
assertThat(actual, is(expected));

Alternatively, use the contains Matcher, which checks that an Iterable contains items in a specific order

import static org.junit.Assert.assertThat;
import static org.hamcrest.Matchers.contains;

ArrayList<Integer> actual = new ArrayList<Integer>();
actual.add(1);
actual.add(2);
assertThat(actual, contains(1, 2)); // passes
assertThat(actual, contains(3, 4)); // fails

If you don't care about the order use containsInAnyOrder instead.

Solution 3 - Java

You are comparing ArrayList<Integer> with int. The correct comparison is:

...
assertThat(actual, hasItem(2));

-- Edit --

I'm sorry, I've read it wrong. Anyway, the signature of hasItems you want is:

public static <T> org.hamcrest.Matcher<java.lang.Iterable<T>> hasItems(T... elements)

i.e., it accepts a variable number of arguments. I'm not sure if an ArrayList<T> is compatible, just guessing here. Try sending each item from the expected list interspersed by comma.

assertThat(actual, hasItems(2,4,1,5,6));

-- Edit 2 --

Just pasting here my comment, there is an equivalent expression for what you want, without using Hamcrest:

assertTrue(actual.containsAll(expected));

Solution 4 - Java

Try

assertThat(actual, hasItems(expected.toArray(new Integer[0])));

to satisfy the matcher signature. No Eclipse around, so this might not work.

Solution 5 - Java

That error message looks like one produced by the javac compiler. I've found in the past that code written using hamcrest just won't compile under javac. The same code will compile fine under, say, the Eclipse compiler.

I think Hamcrest's generics are exercising corner cases in generics that javac can't deal with.

Solution 6 - Java

I just came across the same problem and the following trick worked for me:

  • use import static org.hamcrest.Matchers.hasItems
  • have the hamcrest library before junit in classpath (build path -> order and export)

Solution 7 - Java

You can get this error if you try to replace jUnit's hamcrest with a newer version. For example, using junit-dep together with hamcrest 1.3 requires that use assertThat from hamcrest instead of jUnit.

So the solution is to use

import static org.hamcrest.MatcherAssert.assertThat;

instead of

import static org.junit.Assert.assertThat;

Solution 8 - Java

For these cases when code does compile in Eclipse but javac shows errors please do help hamcrest by providing explicitly type parameter e.g. Matchers.hasItem()

Solution 9 - Java

ArrayList<Integer> expected = new ArrayList<Integer>();
expected.add(1);
expected.add(2);
hasItems(expected);

hasItems(T..t) is being expanded by the compiler to:

hasItems(new ArrayList<Integer>[]{expected});

You are passing a single element array containing an ArrayList. If you change the ArrayList to an Array, then your code will work.

Integer[] expected = new Integer[]{1, 2};
hasItems(expected);

This will be expanded to:

hasItems(1, 2);

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionripper234View Question on Stackoverflow
Solution 1 - JavaClive EvansView Answer on Stackoverflow
Solution 2 - JavaDan GodfreyView Answer on Stackoverflow
Solution 3 - JavafreitassView Answer on Stackoverflow
Solution 4 - JavaRobert MunteanuView Answer on Stackoverflow
Solution 5 - JavaskaffmanView Answer on Stackoverflow
Solution 6 - JavaZsoltView Answer on Stackoverflow
Solution 7 - JavaMikaView Answer on Stackoverflow
Solution 8 - JavamiluchView Answer on Stackoverflow
Solution 9 - JavaUser109377View Answer on Stackoverflow