【问题标题】:Cannot mock annotated field using Mockito无法使用 Mockito 模拟带注释的字段
【发布时间】:2020-03-25 12:12:46
【问题描述】:

以下是被测对象RestClient.java

package com.demo.mockito;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.Validate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.demo.sample1.RestClient;
import com.demo.sample2.AboutApi;
import com.demo.sample3.ServiceInfo;
import com.demo.sample4.FeatureRepo;

@Component
@Slf4j
public class RestClient {

    @Value("${test.api.baseURL:http://localhost:80}")
    private String baseURL;

    private static String ACTIVE = "ACTIVE";

    @Autowired(required = false)
    private TokenService tokenService;

    private FeatureRepo featureRepo;

    RestClient(FeatureRepo featureRepo) {
        this.FeatureRepo = featureRepo;
    }

    public boolean isEnabled() {
        AboutApi aboutApi = new AboutApi(getApiClient());
        ServiceInfo serviceInfo = aboutApi.getMultiSiteServiceInfo();
        Validate.notNull(serviceInfo);
        return ACTIVE.equals(serviceInfo.getStatus());
    }

    private ApiClient getApiClient() {
        ApiClient apiClient = new ApiClient();
        apiClient.setBasePath(baseURL);
        return apiClient;
    }
}

而这个是测试RestClientTest.java

package com.demo.mockito;

import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.powermock.modules.junit4.PowerMockRunner;
import com.demo.sample1.RestClient;
import com.demo.sample2.AboutApi;
import com.demo.sample3.ServiceInfo;
import com.demo.sample4.FeatureRepo;


@RunWith(PowerMockRunner.class)
public class RestClientTest {
    @InjectMocks private RestClient restClient;

    @Mock private AboutApi aboutApiClient;

    @Mock ServiceInfo serviceInfo;

    @Mock FeatureRepo featureRepo;

    @Before
    public void init() throws ApiException {
        when(aboutApiClient.getServiceInfo()).thenReturn(serviceInfo);
        when(serviceInfo.getStatus()).thenReturn("ACTIVE");
    }

    @Test
    public void testIsEnabled() throws ApiException {
        boolean status = restClient.isEnabled();
        assertTrue(status);
    }
}

当我运行测试时,理想情况下,当它到达 RestClient.java 的 isEnabled 方法的第二行时,输出应该按照 @Before 的第一行中的说明进行模拟但它会尝试调用导致 IllegalArgumentException 的真实方法。

谁能告诉我如何在不对文件 RestClient.java 进行任何更改的情况下正确模拟该调用?

【问题讨论】:

  • 你可以添加另一个构造函数来传递两个模拟

标签: java spring junit mockito powermockito


【解决方案1】:

编辑:更新

我在 AboutApi aboutApi = new AboutApi(getApiClient()) 行中有问题。在这里,它调用了一个新实例,而不是使用我模拟的那个。我想知道如何在不接触 RestClient.java 的情况下插入我的 AboutApi 模拟实例

在这种情况下,您必须查看 PowerMockito 的 whenNew 功能。

您必须添加 @PrepareForTest 注释,以便 它包含需要修改的类,在您的情况下为RestClient

@RunWith(PowerMockRunner.class)
@PrepareForTest(RestClient.class)

不确定这是否是您的问题中的错字, 但是您需要为其定义行为的方法应该是 getMultiSiteServiceInfo 而不是 getServiceInfo

@Test
public void testIsEnabled() throws Exception {

    Mockito.when(aboutApiClient.getMultiSiteServiceInfo()).thenReturn(serviceInfo);
    Mockito.when(serviceInfo.getStatus()).thenReturn("ACTIVE");

    PowerMockito.whenNew(AboutApi.class)
                .withAnyArguments()
                .thenReturn(aboutApiClient);

    boolean status = restClient.isEnabled();
    Assert.assertTrue(status);
}

如果您想更具体一些,可以将withAnyArguments() 替换为withArguments(Mockito.any(ApiClient.class))

但请注意,RestClient 类中的字段 tokenServicebaseUrl 将是 null

【讨论】:

  • 我对 InjectMocks 没有任何问题。调试后,我看到 featureRepo 在构造函数调用中被正确地模拟了。我在AboutApi aboutApi = new AboutApi(getApiClient()) 行有问题。在这里,它调用了一个新实例,而不是使用我模拟的那个。我想知道如何在不接触 RestClient.java 的情况下插入我的 AboutApi 模拟实例
  • 我已经通过一个示例更新了答案,说明如何使用PowerMocktiowhenNew 功能来实现这一目标。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-12-12
  • 1970-01-01
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多