1

I'm trying to create a test where I have to mock a method inside the class that I want to test. But it keeps calling the real method, but I want mock it.

The method that I want to mock is

extractSecretValue(String path)

I know it's not mocking the method because there is a "println", and it's printing.

What am I doing wrong?

I'm using JUnit 5

The class that I want to test:

    @Configuration
    public class RestTemplateConfig {

        @Value("${******}")
        private String keystore;

        @Value("${******}")
        private String identificador;

        @Value("${******}")
        private String token;

        @Bean
        public RestTemplate restTemplate() throws NoSuchAlgorithmException, KeyManagementException {
            SSLContext context = null;

            context = SSLContext.getInstance("TLSv1.2");
            context.init(null, null, null);

            List<Header> headers = new ArrayList<>();
            headers.add(new BasicHeader("Authorization", "Bearer " + extractSecretValue(token)));

            CloseableHttpClient httpClient = HttpClientBuilder.create().setSSLContext(context).setDefaultHeaders(headers)
                    .build();

            HttpComponentsClientHttpRequestFactory hcchr = new HttpComponentsClientHttpRequestFactory(httpClient);

            hcchr.setConnectionRequestTimeout(10000);

            return new RestTemplate(hcchr);

        }

        public String extractSecretValue(String path) {

            System.out.println("Test1");
            Path secretPath = Paths.get(path);
            String value = "";
            try (Stream<String> lines = Files.lines(secretPath)) {
                value = lines.collect(Collectors.joining());
            } catch (IOException ignored) {
                throw new ApplicationException(ignored);
            }
            return value.isEmpty() ? path : value;
        }

    }

The Test class:

    @ExtendWith(MockitoExtension.class)
    public class RestTemplateConfigTest {

        @Test
        public void return_restTemplateConfig() {

            RestTemplateConfig restTemplateConfig = new RestTemplateConfig();

            RestTemplateConfig restTemplateMock;

            RestTemplate restTemplate;

            restTemplateMock = Mockito.spy(restTemplateConfig);

            try {
                when(restTemplateMock.extractSecretValue(anyString())).thenReturn("423424");
                restTemplate = restTemplateMock.restTemplate();
            } catch (NoSuchAlgorithmException | KeyManagementException e) {
                throw new ApplicationException(e);
            }

        }

    }

I've already tried this too:

doReturn("2332").when(restTemplateMock).extractSecretValue(anyString());
Lawrence
  • 172
  • 1
  • 9
  • Your mock does not work because it was arranged to expect `anyString` but when invoked `token` is *null* causing the arrangement to not match and default back to the actual method call. – Nkosi Aug 15 '19 at 23:49

3 Answers3

4

If you use when(...).thenReturn(...) the real method will still be invoked
(from Mockito, which is not relevant for your test),
but that should not happen when you use the doReturn(...).when(...) notation instead.

The problem in your test is that token is null and your anyString() does not match that as it only matches non-null strings.

Use any() instead, which matches anything, including nulls.

Combine that with the doReturn(...).when(...) and your test should succeed.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
second
  • 4,069
  • 2
  • 9
  • 24
  • Also please consider renaming your `spy` object. It is different from a (simple) `Mock` so using a name that indicates that improves the readability. – second Aug 15 '19 at 23:56
  • I didn't know "when() thenReturn" would call the real method on spyed objects. I will rename the RestTemplateMock to RestTemplateSpy. Thank you. – Lawrence Aug 16 '19 at 13:51
  • 1
    This behaviour only applies when `spy` is used instead of `mock`, as mentioned [here](https://stackoverflow.com/a/29394497/11514534). – second Nov 05 '19 at 11:40
1

If you do not want the actual methods to be called, then you should be using Mockito.mock() and not Mockito.spy().

you should update your test class to use :

restTemplateMock = Mockito.mock(RestTemplateConfig.class);

Manika
  • 11
  • 2
  • If I do it I think the real method restTemplate() won't be tested. or will it be? I mean, I just want to mock the extractSecretValue. – Lawrence Aug 16 '19 at 13:29
  • Both spy() and mock() can be used to mock objects whereas spy() is a partial mock. The difference between them is better explained here : https://stackoverflow.com/questions/28295625/mockito-spy-vs-mock. Since you are stubbing the method using when()..then() , there is essentially no difference if you use spy(). @Second is correct that since the token was null, actual method invocation was happening. – Manika Aug 18 '19 at 09:15
  • I did it, but my test coverage didn’t update for my class when I used mock, only spy works for me. I stubbed the method extractSecretValue, but I want to test the real method restTemplate. – Lawrence Aug 18 '19 at 22:41
0

You haven't mocked your RestTemplateConfig, you've instantiated it.

What you want is:

restTemplateMock = Mockito.spy(new RestTemplateConfig());

ashyza
  • 1
  • 2
    It doesn't work, keeps calling the real method. But I instantiated restTemplateConfig and then I did Mockito.spy(restTemplateConfig). Should be the same thing. – Lawrence Aug 15 '19 at 22:56