JavaHamcrest icon indicating copy to clipboard operation
JavaHamcrest copied to clipboard

equalTo() does not match correctly with a Long and a IsEqual Matcher for API responses

Open wjtlopez opened this issue 7 years ago • 13 comments

Hello,

We're using your wonderful library to assert on API responses, using RestAssured and Hamcrest.

We are doing the following:

Long expectedId = 1111L
response.then().body("id", equalTo(expectedId))

We are seeing this in the assertion failure message:

Expected: <123456L>
  Actual: 123456

It looks like the String "<123456L>" is coming from the toString() on IsEqual.

Regards, Warren

wjtlopez avatar Sep 07 '18 10:09 wjtlopez

I'm confused. What is the actual value passed to the matcher? Is it a long, or a Long, or a String?

sf105 avatar Sep 08 '18 18:09 sf105

A Long

wjtlopez avatar Sep 18 '18 16:09 wjtlopez

Is there any way we can see the actual code which can be executed and checked. You may provide a basic feature with test case which is failing.

I checked with the Long values and the library works, there may be issue with the RestAssured library instead.

tusharjoshi avatar Dec 08 '18 11:12 tusharjoshi

I'm confused again. Which code do you want to see? As to your original problem, if the actual value is a Long<12345> then that's what the expected value should be, rather than 12345L, as they're actually different types--although Java provides support for implicit conversion.

sf105 avatar Dec 12 '18 11:12 sf105

@sf105 I was asking for "test code" to the original poster so I can reproduce the issue. When I tried to have a Long variable and assert it with equalTo it worked for me, hence asked this question.

tusharjoshi avatar Dec 12 '18 11:12 tusharjoshi

@tusharjoshi Understood. Thanks

sf105 avatar Dec 12 '18 11:12 sf105

@tusharjoshi All we are doing is triggering a response from an API which has a field called id, represented in Java by a Long. It doesn't seem possible to use the equalTo matcher as hopefully depicted in the initial post.

Please let me know if this remains unclear

wjtlopez avatar Feb 14 '19 14:02 wjtlopez

@wjtlopez from your description and code snippet the issue does not seem to be with the hamcrest matcher but with the API you are using. Is there any way you can provide a working code snippet which I can run and check the error. A sample project on github may be using the about mention API only. If we can reproduce the issue then working on the fix if any becomes easier.

tusharjoshi avatar Feb 14 '19 16:02 tusharjoshi

I know exactly what @wjtlopez means. I just had the exactly same problem. The JSON syntax does not differ long from integers, for the JSON syntax both int and long are just an integer number. So take in consideration the following JSON:

{ "id": 12 }

And the bellow assertion:

Long longValue = getLongValue();
response.then().body("id", is(longValue));

A library deserializing the above JSON will create an Integer object to hold the value. But in the JSON bellow the library will create a Long object to hold the value. So sometimes the above test will pass, but sometimes it will not, depending on wheter the value on the id property fits into an int or not.

{ "id": 1125899906842624 }

So the problem is that to check if two values are equal the JavaHamcrest is using the equals method, and the equals method will return false when comparing a Long with and Integer and vice versa.

I suggest the creation of a new matcher that only checks if two objects have any of the types: long, int, char, short, byte. And after checking the types the matcher checks if the integer values from the two objects are equal.

I found the use case for this when writing an integration test using Rest Assured. I can provide more details and code if necessary.

matheusdallrosa avatar Jun 18 '20 03:06 matheusdallrosa

I recently ran into this via:

assertThat(Files.size(saveFile), is(not(0)));

The above is always true. That's because Files.size() returns a long and we get boxing for both sides, so it becomes equivalent to:

assertThat(Long.valueOf(0), is(not(Integer.valueOf(0))));

Since the types don't match, the is(not()) always evaluates to true, making the test buggy.

Using 0L in the original code fixes it, but it's a pretty bad a foot gun.

asvitkine avatar Apr 01 '22 01:04 asvitkine

Ouch. Not sure what we can do about that. In meantime, I tend to use the JUnit assertNotEquals() for simple comparison.s

sf105 avatar Apr 01 '22 08:04 sf105