3

Here's the code:

public final class APIClient {
    private static Identity identity = createIdentity();

    private static Identity createIdentity() {
        CredentialsProvider provider = new CredentialsProvider(API_USER);
        Credentials creds = provider.getCredentials();

        identity = new Identity();
        identity.setAttribute(Identity.ACCESS_KEY, creds.getAccessKeyId());
        identity.setAttribute(Identity.SECRET_KEY, creds.getSecretKey());

        return identity;
    }

}

How can I mock a CredentialsProvider when unit test:

@Test
public void testCreateAPIClient() {
    // mock a CredentialsProvider
    client = new APIClient();
    Assert.assertNotNull(client);
}

Thanks in advance!

LittleQ
  • 1,860
  • 1
  • 12
  • 14
  • 2
    What you can do is to create a new method, for example `createCredentialProviderInstance()` and then just mock the whole class and override the method that creates the instance – Tuchkata Jul 27 '16 at 06:28
  • Possible duplicate of [How to test a class that has private methods, fields or inner classes?](http://stackoverflow.com/questions/34571/how-to-test-a-class-that-has-private-methods-fields-or-inner-classes) – Raedwald Jul 28 '16 at 08:42
  • 2
    Tuchkata is correct: the code that you are showing is really hard to test. You should put such functionality into a dedicated factory/provider. Sure, you still have that 3rd party static call you need to PowerMock ... but don't fall into the same trap; instead make sure that at least your **own** code is testable ( see https://www.youtube.com/playlist?list=PLD0011D00849E1B79 to get some inspiration on that) – GhostCat Jul 28 '16 at 09:17
  • initialize dependencies by creating `new` instead of apply `Dependency Injection` will make its hard to mock, you should first apply `Dependency Injection` for `CredentialsProvider` then you will decide [ Test third-party APIs vs. Mock third-party APIs] – Ahmed Nabil Jan 26 '19 at 12:00

1 Answers1

3

Check the powermock documentation, depending on what you use, either mockito or easy mock. Below a sample based on mockito and a slightly modified version of your classes

import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.powermock.api.mockito.PowerMockito.*;

// use appropriate test runner
@RunWith(PowerMockRunner.class)
// prepare the class calling the constructor for black magic
@PrepareForTest(APIClient.class)
public class APIClientTest {

    @Test
    public void testCreateAPIClient() throws Exception {
        // expectations
        String expectedAccessKey = "accessKeyId";
        String expectedSecretKey = "secretKey";
        Credentials credentials = new Credentials(expectedAccessKey, expectedSecretKey);

        // create a mock for your provider
        CredentialsProvider mockProvider = mock(CredentialsProvider.class);

        // make it return the expected credentials
        when(mockProvider.getCredentials()).thenReturn(credentials);

        // mock its constructor to return above mock when it's invoked
        whenNew(CredentialsProvider.class).withAnyArguments().thenReturn(mockProvider);

        // call class under test
        Identity actualIdentity = APIClient.createIdentity();

        // verify data & interactions
        assertThat(actualIdentity.getAttribute(Identity.ACCESS_KEY), is(expectedAccessKey));
        assertThat(actualIdentity.getAttribute(Identity.SECRET_KEY), is(expectedSecretKey));
    }

}
Morfic
  • 15,178
  • 3
  • 51
  • 61