使用Mockito模拟Unirest请求

3

我正在我的编程起步阶段,想要询问关于使用Mockito模拟对象的问题,更具体地说是Unirest返回的响应对象。 假设我有一个数据库,我不想每次进行测试时都要麻烦它,而我想使用Mockito来解决这个问题,但问题是我不确定如何创建虚假的“httpResponse”对象来返回。 为了提供一些上下文,我附上了我的代码:

    /**
 * This method lists the ID of the activity when requested.
 *
 * @return the list of all activities
 */
public  JSONArray getActivites() {
    HttpResponse<JsonNode> jsonResponse = null;
    try {
        jsonResponse = Unirest
                .get("http://111.111.111.111:8080/activity")
                .header("accept", "application/json")
                .asJson();
    } catch (UnirestException e) {
        System.out.println("Server is unreachable");
    }

    JSONArray listOfActivities = jsonResponse.getBody().getArray();
    return listOfActivities;
}

所以我想的是,模拟Unirest,当调用.get方法时,返回一个假的HttpResponse。问题是,我不确定如何做到这一点,我在网上查找了一些资料,但并没有明白太多。

有没有可能用实际的数据库进行一次测试,并“提取”信息,以便每次测试时使用?


要模拟static方法,您需要使用PowerMockito - Lino
5个回答

6
使用PowerMockRunner、PowerMockito和Mockito的示例代码片段
@RunWith(PowerMockRunner.class)
    @PrepareForTest({ Unirest.class})
    public class TestApp{

      @Before
      public void setup() {
        PowerMockito.mockStatic(Unirest.class);
      }

      @Test
      public void shouldTestgetActivites() throws UnirestException {
        when(Unirest.get(Client.DEFAULT_BASE_URL)).thenReturn(getRequest);
        when(getRequest.asJson()).thenReturn(httpResponse);
        when(httpResponse.getStatus()).thenReturn(Integer.valueOf(200));

        assertThat(something).isEqualTo(true);
      }

    }

所以我一直在看你的代码片段,在这一行中: when(Unirest.get(Client.DEFAULT_BASE_URL)).thenReturn(getRequest); 我不明白当调用Unirest.get时会返回什么样的“getRequest”。那个“getRequest”对象是什么? - Bar Lerer
@BarLerer 是的。这是一个 GetRequest 的模拟。您可以参考此链接获取更多详细信息。https://github.com/thejamesthomas/javabank/blob/master/javabank-client/src/test/java/org/mbtest/javabank/ClientTest.java - Mebin Joe

2
与此同时,原始作者使用unirest-mocks提供嘲弄支持:unirest-mocks
Maven:
<dependency>
    <groupId>com.konghq</groupId>
    <artifactId>unirest-mocks</artifactId>
    <version>LATEST</version>
    <scope>test</scope>
</dependency>

使用方法:

class MyTest {
    @Test
    void expectGet(){
        MockClient mock = MockClient.register();

        mock.expect(HttpMethod.GET, "http://zombo.com")
                        .thenReturn("You can do anything!");
        
        assertEquals(
            "You can do anything!", 
            Unirest.get("http://zombo.com").asString().getBody()
        );
        
        //Optional: Verify all expectations were fulfilled
        mock.verifyAll();
    }
}

很遗憾,它不起作用。HttpMethod.GET 应该来自 kong.unirest.HttpMethod,但在 jar 文件中不存在。我尝试了 <version>3.11.09</version>。 - Rita
@Rita kong.unirest.HttpMethod<artifactId>unirest-java</artifactId> 的真实对象。在 unirest-mocks 中,该依赖项被标记为“provided”,因此必须将其添加到项目的 pom.xml 文件中。 - timomeinen

2

与其直接调用静态成员,您可以将调用包装在一个包装类中,该类可以根据一些参数提供HttpResponse。这是一个接口,可以在Mockito中轻松模拟。

/**
 * This is a wrapper around a Unirest API.
 */
class UnirestWrapper {

    private HttpResponse<JsonNode> getResponse(String accept, String url) {
        try {
            return Unirest
                .get(url)
                .header("accept", accept)
                .asJson();
        } catch (UnirestException e) {
            System.out.println("Server is unreachable");
        }
        // Or create a NULL HttpResponse instance.
        return null;
    }
}

private final UnirestWrapper unirestWrapper;

ThisClassConstructor(UnirestWrapper unirestWrapper) {
    this.unirestWrapper = unirestWrapper;
}

/**
 * This method lists the ID of the activity when requested.
 *
 * @return the list of all activities
 */
public JSONArray getActivites() {
    HttpResponse<JsonNode> jsonResponse = this.unirestWrapper.getResponse("http://111.111.111.111:8080/activity", "application/json");

    if (jsonResponse == null) {
        return null;
    }

    JSONArray listOfActivities = jsonResponse.getBody().getArray();
    return listOfActivities;
}

或者你可以使用 Power Mocks...


0

我使用JUnit5和Mockito解决了类似的任务。 测试的类:

@Service
@RequiredArgsConstructor
@Profile("someProfile")
@Slf4j
public class SomeService {
    
    @Value("${value1}")
    private final String value1;

    @Value("${value2}")
    private final String value2;

    private final ObjectMapper mapper;
    private final CommonUtil commonUtil;

    public boolean methodUnderTest(String inputValue) {
        HttpResponse<String> result;
        //some logic 
        try {
            result = Unirest.get("url")
                    .header(header, value)
                    .routeParam("param", paramValue)
                    .asString();
            if (result.getStatus() != 200) {
                throw new MyException("Message");
            }
            //some logic
        } catch (Exception e) {
            log.error("Log error", e);
            //some logic
        }
    }
}

并测试:

@ExtendWith(MockitoExtension.class)
class SomeServiceTest {
    @Mock
    private CommonUtil commonUtil;
    @Mock
    private ObjectMapper mapper;
    @Mock
    HttpResponse httpResponse;
    @Mock
    GetRequest request;

    private SomeService serviceUnderTest;


    @BeforeEach
    void setUp() {
        this.serviceUnderTest = new SomeService("url", "valu1", mapper, commonUtil);
    }

    @Test
    void methodUnderTest_whenSmth_ThenSmth() throws UnirestException {
        try (MockedStatic<Unirest> unirest = Mockito.mockStatic(Unirest.class)) {
            unirest.when(() -> Unirest.get(anyString()))
                    .thenReturn(request);

            Mockito.when(commonUtil.encodeValue(Mockito.anyString())).thenReturn("123");

            Mockito.when(request.header(anyString(), anyString())).thenReturn(request);
            Mockito.when(request.routeParam(anyString(), anyString())).thenReturn(request);
            Mockito.when(request.asString()).thenReturn(httpResponse);


            Mockito.when(httpResponse.getStatus()).thenReturn(200);
            Mockito.when(httpResponse.getBody()).thenReturn("true");
            assertTrue(serviceUnderTest.methodUnderTest("123"));
        }
    }
 }   

0
你可以使用 Mockito.mock(HttpResponse.class) 模拟 HttpResponse,并在获取该响应的正文时放置相应的 JSON。例如:
HttpResponse response = Mockito.mock(HttpResponse.class);    
when(response.getBody()).thenReturn(readFileContent("my_response.json"));

这个 'readFileContent' 方法只是用来读取文件并获取响应的。你可以将你的 JSON 放在那里进行比较。


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