3

I have the following definition in my code based on Spring Integration enrichHeader with randomUUID:

@Bean
public Consumer<HeaderEnricherSpec> uriHeaderEnricher() {
    return new Consumer<HeaderEnricherSpec>() {
        private final String TIMESTAMP = "Timestamp";
        private final String MESSAGE_ID = "MessageId";

    @Override
        public void accept(HeaderEnricherSpec t) {
            t.headerFunction(MarklogicMessageHandler.URI, 
                    m -> "/event/" +
                         format(m.getHeaders().get(TIMESTAMP)) + "/" +
                         m.getHeaders().get(MESSAGE_ID) +
                         ".xml");
        }

        private String format(Object object) {
            if (!(object instanceof String)) {
                return "";
            }
            String string = (String) object;
            return string.substring(0, 10).replaceAll("-", "/");
        }

    };
}

I'm a bit stymied, though on what a unit test for this code would look like. Any suggestions?

officer
  • 2,080
  • 1
  • 20
  • 29
Don Hosek
  • 981
  • 6
  • 23

1 Answers1

4

So we want to isolate the class under test Consumer<HeaderEnricherSpec> and assert on any and all interactions that class has with other classes, in this case HeaderEnricherSpec. I'm not sure if you're using a mocking framework like Mockito or not, but I can give you an example in Mockito of how to test this well. The thing that is going to prove interesting is using an ArgumentCaptor to capture the lambda sent to headerFunction and then you can call that lambda in your test to ensure it is working as expected.

//This should invoke your bean method
@Autowired
private Consumer<HeaderEnricherSpec> consumer;

@Captor
private ArgumentCaptor<Function<WhateverTypeMIs, String>> lambdaCaptor; 

@Test
public void testAccept() {
    HeaderEnricherSpec spec = Mockito.mock(HeaderEnricherSpec.class);

    consumer.accept(spec);

    // Just showing you how to use the captor, don't forget to test URI
    verify(spec).headerFunction(any(), lambdaCaptor.capture());

    //This will be the lambda function you passed to `headerFunction`
    Function<WhateverTypeMIs, String> lambda = lambdaCaptor.getValue();

    //Now you need to call the lambda function just like you would if it were a separately testable function.
    String result = lambda.apply(m);
    //assertions on result string based on m input
}

Let me know if you need more help or guidance.

More info on ArgumentCaptor: docs, StackOverflow Answer

Using ArgumentCaptor as field

Jack
  • 91
  • 4
  • Note: I did not compile this code so treat it as such. – Jack Jun 12 '17 at 22:16
  • The verify line is giving me an error. It doesn't like the any() (putting an empty string let the compiler past that) I then get the following error on headerfunction: `The method headerFunction(String, Function, Object>) in the type HeaderEnricherSpec is not applicable for the arguments (String, Function, Object>)` (I also had to make some type changes in the definition of lambdaCaptor). – Don Hosek Jun 14 '17 at 15:11
  • Hmmm, without trying to recreate your situation, my guess is that the compiler is unable to ensure the generic type of `Message` to be `P`. Maybe try making your captor loose and use `Object` instead of `P` for the generic type of `Message` and you may get passed this warning. This may put you in a position to have to cast back to `P` later, however. – Jack Jun 14 '17 at 16:11
  • I think it might be a Mockito bug--the P is a generic specification on the headerFunction definition – Don Hosek Jun 14 '17 at 18:01
  • Yeah that does seem strange then. Did you try changing it to Object? – Jack Jun 14 '17 at 21:42
  • Changing what to object? If you mean the generic parameter on Message where I had control over it, yes, I did. – Don Hosek Jun 15 '17 at 20:40
  • It turns out the issue was the compiler wasn't correctly notifying me that I was using the wrong `Function` class. – Don Hosek Jun 19 '17 at 15:29
  • Ahhh, I see. That's always a frustrating problem. Glad you figured it out! Cheers. – Jack Jun 20 '17 at 16:27