3

I have the following object graph:

Order --> List of Lines --> List of Shipments object

The Line object has an attribute called lineNumber. The Shipment object also has an attribute called lineNumber. I don't know why they have it on both, but those are the cards I have been dealt with.

Would it be possible to compare that the line.getLineNumber().equals(shipment.getLineNumber()) for each line?

So in effect, I want to test the following:

for(Line line : order.getLines(){
    for(Shipment ship : line.getShipments()) {
         assertEquals(line.getLineNumber(), shipment.getLineNumber());
    }
}

I tried the following, but it didn't work:

assertThat(order.getLines(), everyItem(Matchers.<Line>hasProperty("shipments", everyItem(Matchers.<Shipment>hasProperty("lineNumber", is(line.getLineNumber())))))

Obviously, I don't have a reference to line, so how would I compare the values in this case?

Inxsible
  • 700
  • 5
  • 27

2 Answers2

0

assertThat takes exactly two parameters (well, three, but the third one would just be the message to print for fails):

  1. actual value (so, yes, getLines()) is OK there
  2. expected value, which should be some form of matcher

So your idea of adding multiple "expected matchers" to the same call simply doesn't work.

You got:

assertThat(a1, e1, e2, e3);

Instead: split up your single call with assertThat into several ones - one for each "expected" condition you want to check.

assertThat(a1, e1;
assertThat(a1, e2);...

If the above doesn't help, or if you wish to write code that only requires a single assertThat, you can always go forward and write your own customer matcher, for example starting with the simple solution I put together for some other question.

For the record: that was my first custom matcher, and I got it working in less than 10 minutes; in other words: that is a pretty easy task once you are into the concepts!

Community
  • 1
  • 1
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • Fair enough. I don't have to do everything in 1 line, but I am still unsure if the lineNumber attribute at the line level can be compared with the one at the shipment level, without me explicitly saving the line number in a local variable in a for loop and then comparing that in the everyItem clause for the Shipment object. – Inxsible Oct 06 '16 at 16:40
  • Then you are asking us to **interpret** your requirements; and your existing source code. Nobody around here can tell you **if** it makes sense to compare these values. If there is a constraint that they should be equal, then that it something within your context. We can only help with "how to do things"; not with "what to do". The "what" is **your** context. – GhostCat Oct 06 '16 at 19:00
0

Not exactly what you are looking for, but at least fits in one line:

    order.getLines().forEach(
        l -> 
          assertThat(l.getShipments(), 
             everyItem(
                  hasProperty("lineNumber", is(l.getLineNumber())))));

As you say, it could be great to have matchers holding references to the object being examined, but I would not know how to do it with Hamcrest.

Ruben
  • 3,986
  • 1
  • 21
  • 34
  • yes that is along the lines that I was thinking on, but it seems hamcrest doesn't have the capability to hold references to the object as you mentioned. too bad ! – Inxsible Oct 18 '16 at 19:23