Mockito verify fails, shows additional empty line

Mockito verify fails, shows additional empty line

When running JUnit tests on a legacy code base at work I got the familiar “Argument(s) are different! [….] Actual invocation has different arguments” notice from Mockito. I ran the tests from the command line, but as I could see no difference between the expected and actual output I re-ran the tests inside IntelliJ to investigate further, resulting in this:

Notice the trailing newline in the actual request made.

From the reported error above it wasn’t straight forward figuring out the underlying issue, so I though I’d share this quick write-up just in case others stumble on the same issue.

Extract from the test code:

String expectedSoapRequest = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn1=\"urn:com.acme.system:S-1-0\" xmlns:urn=\"urn:com.acme.system:S-1-0\">\n" +
                "    <soapenv:Body>\n" +
                "        <urn1:SMSRequest>\n" +
                "            <urn:id>1234567890</urn:id>\n" +
                "            <urn:timestamp>1623137600000</urn:timestamp>\n" +
                "            <urn:destination>1234</urn:destination>\n" +
                "            <urn:originator>99999999</urn:originator>\n" +
                "            <urn:service>TEST</urn:service>\n" +
                "            <urn:message>message</urn:message>\n" +
                "        </urn1:SMSRequest>\n" +
                "    </soapenv:Body>\n" +
                "</soapenv:Envelope>";

        HttpHeaders headers = new HttpHeaders();
        headers.set(AUTHORIZATION, "Basic " + encodeBasicAuth(config.getUsername(), config.getPassword(), UTF_8));
        HttpEntity<String> expectedHttpEntity = new HttpEntity<>(expectedSoapRequest, headers);
        verify(restTemplateMock).exchange(eq(url), eq(POST), eq(expectedHttpEntity), eq(String.class));

This test ran fine on my coworker’s linux systems, but on my Windows laptop it failed with the above newline issue. After debugging the issue I found that the issue was related to the use of “\n” in the test code.

Extract from the production code:

private String buildSoapRequest(Message message) {
        String xmlTemplate =
                "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn1=\"urn:com:acme:system:S-1-0\" xmlns:urn=\"urn:com.acme.system:S-1-0\">%n" +
                        "    <soapenv:Body>%n" +
                        "        <urn1:SMSRequest>%n" +
                        "            <urn:id>%s</urn:id>%n" +
                        "            <urn:timestamp>%d</urn:timestamp>%n" +
                        "            <urn:destination>%s</urn:destination>%n" +
                        "            <urn:originator>%s</urn:originator>%n" +
                        "            <urn:service>%s</urn:service>%n" +
                        "            <urn:message>%s</urn:message>%n" +
                        "        </urn1:SMSRequest>%n" +
                        "    </soapenv:Body>%n" +
                        "</soapenv:Envelope>";

        return String.format(
                xmlTemplate,
                message.getId(),
                message.getTimestamp(),
                message.getDestination(),
                message.getOriginator(),
                message.getService(),
                StringEscapeUtils.escapeXml11(message.getMessage()));
    }

Notice the production code’s use of “%n” versus the test code’s use of “\n”. On linux systems both yields the same result, but on Windows systems they don’t. The fix was easy:

<!-- wp:code {"lineNumbers":false} -->
<pre class="wp-block-code"><code lang="java" class="language-java">String expectedSoapRequest = "&lt;soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:urn1=\"urn:com.acme.system:S-1-0\" xmlns:urn=\"urn:com.acme.system:S-1-0\">%n" +
                "    &lt;soapenv:Body>%n" +
                "        &lt;urn1:SMSRequest>%n" +
                "            &lt;urn:id>1234567890&lt;/urn:id>%n" +
                "            &lt;urn:timestamp>1623137600000&lt;/urn:timestamp>%n" +
                "            &lt;urn:destination>1234&lt;/urn:destination>%n" +
                "            &lt;urn:originator>99999999&lt;/urn:originator>%n" +
                "            &lt;urn:service>TEST&lt;/urn:service>%n" +
                "            &lt;urn:message>message&lt;/urn:message>%n" +
                "        &lt;/urn1:SMSRequest>%n" +
                "    &lt;/soapenv:Body>%n" +
                "&lt;/soapenv:Envelope>";

String expectedFormattedRequest = String.format(expectedSoapRequest);

        HttpHeaders headers = new HttpHeaders();
        headers.set(AUTHORIZATION, "Basic " + encodeBasicAuth(config.getUsername(), config.getPassword(), UTF_8));
        HttpEntity&lt;String> expectedHttpEntity = new HttpEntity&lt;>(expectedFormattedRequest, headers);
        verify(restTemplateMock).exchange(eq(url), eq(POST), eq(expectedHttpEntity), eq(String.class));</code></pre>
<!-- /wp:code -->

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.