java - Mockito:监视被测系统中依赖于 HTTP 请求的方法是不好的做法吗?

标签 java unit-testing testing mockito

通过阅读,当您必须监视您正在单元测试的当前方法所使用的方法时,通常会出现不良做法和代码异味的迹象。

例如,我有这个正在单元测试的方法:

public MyResponseObject doStuff(MyRequestObject obj) {
    WebTarget tar = getServiceClient().target(obj.toString());
    Response res = tar.path(someURI).request().post(somejson);
    if(response.getStatus() == 200) {
        String jsonResp = response.readEntity(String.class);
        return convertToObj(jsonResp);
    }
}

我试图解决上述问题的一种方法是

  1. 将前两行(WebTarget、Response)提取到它自己的方法中,该方法返回一个 Response 对象。
  2. 创建 Response 的模拟并 stub readEntity 以返回 200 和 stub readEntity 以返回“OK”

结果如下:

public MyResponseObject doStuff(MyRequestObject obj) {
    Response res = sendRequest(obj.toString());
    if(response.getStatus() == 200) {
        String jsonResp = response.readEntity(String.class);
        return convertToObj(jsonResp);
    }
}

//extracted method
public Response sendRequest(String json){
    WebTarget tar = getServiceClient().target(someUrl);
    return res = tar.path(someURI).request().post(somejson);
}

//My unit test

//sut is the system under test, setup elsewhere
public void testDoStuff() {
    MyRequestObject request = ...;
    Response respMock = mock(Response.class);
    when(respMock.getStatus()).thenReturn(200);
    when(respoMock.readEntity()).thenReturn("OK");
    MyClass spy = spy(sut);
    Mockito.doReturn(respMock).when(spy).sendRequest(requestString);
    MyResponseObject  response = spy.doStuff(request);

    assertEquals(response.toString(),expectedResp);
}

如果我不把它 stub ,它会尝试做一个真正的 HTTP 请求并返回一个无效的 URL 错误,因为我没有提供一个真正的错误——我相信这就是我想要的,因为我希望我的单元测试是独立于一些外部系统。

有没有更好的方法来进行我的单元测试?

最佳答案

是的,创建一个你正在测试的类的 spy 是不好的做法,将你正在模拟的代码分解到另一个类中并模拟它,即:

public class MyClass {

    private final MySender sender;

    public MyClass() {
        this(new DefaultSender());
    }

    public MyClass(MySender sender) {
        this.sender = sender;
    }

    public MyResponseObject doStuff(MyRequestObject obj) {
        Response res = sender.sendRequest(obj.toString());
        if (response.getStatus() == 200) {
            String jsonResp = response.readEntity(String.class);
            return convertToObj(jsonResp);
        }
    }

    public interface MySender {
        Response sendRequest(String json);
    }

    private static class DefaultSender implements MySender {
        public Response sendRequest(String json) {
            WebTarget tar = getServiceClient().target(someUrl);
            return res = tar.path(someURI).request().post(somejson);
        }
    }
}

@RunWith(MockitoJUnitRunner.class)
public class MyClassTest {

    private MyClass testSubject;

    @Mock
    private MySender sender;

    @Mock
    private Response response;

    @Test
    public void testDoStuff() {
        String expectedResp = ...;
        MyRequestObject request = ...;
        MyResponseObject  response = testSubject.doStuff(request);

        assertEquals(response.toString(),expectedResp);
    }

    @Before
    public void setup() {
        testSubject = new MyClass(sender);
        when(sender.sendRequest(anyString()).thenReturn(response);
        when(response.getStatus()).thenReturn(200);
        when(response.readEntity()).thenReturn("OK");
    }
}

关于java - Mockito:监视被测系统中依赖于 HTTP 请求的方法是不好的做法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53671685/

相关文章:

c# - Visual Studio项目目录

Python:如何为单元测试模拟kafka主题?

java - 如何在运行时定义 JUnit 测试超时(即没有注释)?

unit-testing - 我如何在单元测试中限制/门内存使用

javascript - 以用户体验为中心的 Web 应用程序回归测试的工具和技术?

java - 服务器上适用于 JDK 的 Eclipse IDE

java - 如何在 java 中移动 char 数组的值?

java - 在 Spring Boot 应用程序中通过 Jersey 资源方法提供静态内容

java - 如何防止使用 JPA 保存子对象?

python - Django 1.11 : What fails `pickle` in my parallel test run?