如何在私有静态方法中模拟第三方类?

3
这里是代码:

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;
    }

}

我该如何在单元测试中模拟CredentialsProvider
@Test
public void testCreateAPIClient() {
    // mock a CredentialsProvider
    client = new APIClient();
    Assert.assertNotNull(client);
}

感谢您的提前帮助!

2
你可以创建一个新的方法,例如 createCredentialProviderInstance(),然后只需模拟整个类并覆盖创建实例的方法。 - Tuchkata
可能是此问题的重复:如何测试具有私有方法、字段或内部类的类? - Raedwald
2
Tuchkata是正确的:您展示的代码确实很难测试。您应该将这样的功能放入专用工厂/提供程序中。当然,您仍然需要PowerMock来调用第三方静态方法...但不要陷入同样的陷阱;相反,请确保至少您自己的代码可测试(请参见https://www.youtube.com/playlist?list=PLD0011D00849E1B79以获取一些灵感)。 - GhostCat
通过创建new来初始化依赖项而不是应用Dependency Injection会使模拟变得困难,因此您应该首先为CredentialsProvider应用Dependency Injection,然后再决定[测试第三方API vs.模拟第三方API]。 - Ahmed Nabil
1个回答

3

请查看PowerMock文档,根据您使用的是mockito还是easy mock进行操作。以下是基于Mockito和您的类的略微修改版本的示例:

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));
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接