简体   繁体   English

模拟HTTP客户端请求的HTTP服务器超时

[英]Simulate HTTP server time out for HTTP client request

In reference to: HttpURLConnection timeout question 参考: HttpURLConnection超时问题

-> Any idea on how to automate the unit test case for the above? - >关于如何自动化上述单元测试用例的任何想法?

More specifically, if the HTTP client has set 5 seconds as its timeout, I want the server to send the response after 10 seconds. 更具体地说,如果HTTP客户端将超时设置为5秒,我希望服务器在10秒后发送响应。 This would ensure my client would fail due to time out and thus automating this scenario. 这将确保我的客户端因超时而失败,从而自动化此方案。

I would appreciate the psuedo code for the server side (any light weight http server such as jetty or any other is fine). 我会很感激服务器端的伪代码(任何轻量级的http服务器,如jetty或任何其他很好)。

You don't want to actually connect to a real server in a unit test. 您不希望在单元测试中实际连接到真实服务器。 If you want to actually connect to a real server, that is technically an integration test. 如果您想实际连接到真实服务器,那么从技术上讲,这是一个集成测试。

Since you are testing the client code, you should use a unit test so you don't need to connect to a real server. 由于您正在测试客户端代码,因此您应该使用单元测试,这样您就不需要连接到真实服务器。 Instead you can use mock objects to simulate a connection to a server. 相反,您可以使用模拟对象来模拟与服务器的连接。 This is really great because you can simulate conditions that would be hard to achieve if you used a real server (like the connection failing in the middle of a session etc). 这真的很棒,因为你可以模拟如果使用真实服务器很难实现的条件(比如在会话中间连接失败等)。

Unit testing with mocks will also make the tests run faster since you don't need to connect to anything so there is no I/O delay. 使用模拟进行单元测试也会使测试运行得更快,因为您不需要连接任何东西,因此没有I / O延迟。

Since you linked to another question, I will use that code example (repasted here for clarity) I made a class called MyClass with a method foo() that connects to the URL and returns true or false if the connection succeeded. 由于您链接到另一个问题,我将使用该代码示例(为了清楚起见,这里重新编写)我使用方法foo()创建了一个名为MyClass的类,该方法连接到URL并在连接成功时返回true或false。 As the linked question does: 正如相关问题所做的那样:

public class MyClass {

private String url = "http://example.com";

public boolean foo(){
    try {
           HttpURLConnection.setFollowRedirects(false);
           HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
           con.setRequestMethod("HEAD");

           con.setConnectTimeout(5000); //set timeout to 5 seconds

           return (con.getResponseCode() == HttpURLConnection.HTTP_OK);
        } catch (java.net.SocketTimeoutException e) {
           return false;
        } catch (java.io.IOException e) {
           return false;
        }

    }
}

I will use Mockito to make the mock objects since that is one of the more popular mock object libraries. 我将使用Mockito来制作模拟对象,因为这是一个比较流行的模拟对象库。 Also since the code creates a new URL object in the foo method (which isn't the best design) I will use the PowerMock library which can intercept calls to new . 此外,由于代码在foo方法中创建了一个新的URL对象(这不是最好的设计),我将使用PowerMock库来拦截对new调用。 In a real production code, I recommend using dependency injection or at least method extraction for creating the URL object to a factory method so you can override it to ease testing. 在实际的生产代码中,我建议使用依赖注入或至少方法提取来创建工厂方法的URL对象,以便您可以覆盖它以简化测试。 But since I am keeping with your example, I won't change anything. 但既然我坚持你的榜样,我就不会做任何改变。

Here is the test code using Mockito and Powermock to test timeouts: 以下是使用Mockito和Powermock测试超时的测试代码:

import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;    
import java.net.URL;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.*;

@RunWith(PowerMockRunner.class)
//This tells powermock that we will modify MyClass.class in this test 
//- needed for changing the call to new URL
@PrepareForTest(MyClass.class) 
public class ConnectionTimeOutTest {

String url = "http://example.com";
@Test
public void timeout() throws Exception{
    //create a mock URL and mock HttpURLConnection objects
    //that will be our simulated server
    URL mockURL = PowerMockito.mock(URL.class);
    HttpURLConnection mockConnection = PowerMockito.mock(HttpURLConnection.class);

    //powermock will intercept our call to new URL( url) 
    //and return our mockURL object instead!
    PowerMockito.whenNew(URL.class).withArguments(url).thenReturn(mockURL);
    //This tells our mockURL class to return our mockConnection object when our client
    //calls the open connection method
    PowerMockito.when(mockURL.openConnection()).thenReturn(mockConnection);



    //this is our exception to throw to simulate a timeout
    SocketTimeoutException expectedException = new SocketTimeoutException();

    //tells our mockConnection to throw the timeout exception instead of returnig a response code
    PowerMockito.when(mockConnection.getResponseCode()).thenThrow(expectedException);

    //now we are ready to actually call the client code
    // cut = Class Under Test
    MyClass cut = new MyClass();

    //our code should catch the timeoutexception and return false
    assertFalse(cut.foo());

   // tells mockito to expect the given void methods calls
   //this will fail the test if the method wasn't called with these arguments
   //(for example, if you set the timeout to a different value)
    Mockito.verify(mockConnection).setRequestMethod("HEAD");
    Mockito.verify(mockConnection).setConnectTimeout(5000);

}
}

This test runs in less than a second which is much faster than having to actually wait for over 5 seconds for a real timeout! 这个测试在不到一秒的时间内运行,这比实际超时实际等待超过5秒要快得多!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM