2010-10-04 27 views
5

要求比方说,我正在写一个应用程序,我需要能够做这样的事情:模拟HTTPS在Java

String url = "https://someurl/"; 
GetMethod method = new GetMethod(URLEncoder.encode(url)); 
String content = method.getResponseBodyAsString(); 

有没有一种方法,以提供一个模拟服务器,将让我处理https请求?我正在寻找的是一种编写单元测试的方法,但我需要能够模拟实际发送到https://someurl的部分,以便我可以获得已知的响应。

+0

http://stackoverflow.com/q/393099/2093341 – Andrea 2013-06-13 10:21:01

回答

3

你基本上有两种选择:

1.摘要调用框架和测试这一点。

E.g.重构代码以允许您在某个时刻注入模拟实现。有很多方法可以做到这一点。例如创建一个getUrlAsString()并模拟它。 (也在上面建议)。或者创建一个返回GetMethod对象的url getter工厂。工厂可以被嘲笑。

2.启动应用服务器作为测试的一部分,然后针对它运行您的方法。 (这将是更多的集成测试)

这可以通过多种方式实现。这可能在测试的外部,例如maven码头插件。或者测试可以以编程方式启动服务器。请参阅:http://docs.codehaus.org/display/JETTY/Embedding+Jetty

通过https运行它会使这个过程复杂化,但它仍然可以使用自签名证书。但我会问自己 - 你想测试什么?我怀疑你实际上是否需要测试https功能,这是一项成熟的技术。

就我个人而言,我会选择1 - 你试图测试外部库的功能。这通常是不必要的。将您的依赖关系抽象到外部库也是很好的做法。

希望这会有所帮助。

1

看看JWebUnit的http://jwebunit.sourceforge.net/

下面是测试的一个例子......它真的很直观。

public class ExampleWebTestCase extends WebTestCase { 
    public void setUp() { 
     super.setUp(); 
     setBaseUrl("http://localhost:8080/test"); 
    } 

    public void test1() { 
     beginAt("/home"); 
     clickLink("login"); 
     assertTitleEquals("Login"); 
     setTextField("username", "test"); 
     setTextField("password", "test123"); 
     submit(); 
     assertTitleEquals("Welcome, test!"); 
    } 
} 
+0

的可能的复制,是的,我熟悉JWebUnit的,但在这里我需要能够嘲笑实际的URL被服务向上。 JWebUnit在您调用的网站/服务正在运行时工作。 – dcp 2010-10-04 18:21:55

1

你总是可以推出thttpd服务器作为单元测试在本地请求提供服务的一部分。虽然,理想情况下,你有一个经过良好测试的GetMethod,然后你可以嘲笑它,而不必真的拥有一个远程服务器来进行所有的测试。

资源

1

你可以用一些类的代码,并有WebClient.getUrl(),然后嘲笑(例如,jmock),该方法返回保存的文件 - 说

expectation { 
    oneOf("https://someurl/"), will(returnValue(someHTML)); 
} 
2

如果你正在编写单元测试,你不要w蚂蚁的任何外部依赖。从API,

GetMethod 

延伸

HttpMethod 

这样你就可以轻松地与您喜爱的嘲弄库嘲笑它。你的

method.getResponseBodyAsString() 

调用可以被嘲笑返回任何你想要的数据。

+0

但GetMethod正在代码本身中创建,而不是在我的单元测试中,所以我不能嘲笑它。 – dcp 2010-10-04 18:20:54

+0

我不明白,你不控制你正在测试的代码? – hvgotcodes 2010-10-04 18:30:28

+0

我控制代码,但GetMethod对象正在我正在测试的方法内部创建,所以我无法传入模拟对象。模拟工作的方式是事先设置它并将它传递给你正在测试的任何方法,但是在这种情况下,GetMethod对象是在方法本身内部创建的,所以我不能传入它。如果它是不清楚,请让我知道。 – dcp 2010-10-04 18:43:21

1

静态页面到什么扩展您有兴趣在嘲讽这种“获取”的呼叫,因为如果你正在寻找一个一般Java与JUnit很好地集成在一起,可以设置在JUnit套件中自动声明的期望,然后您应该看看jMock

现在没有更多的代码,很难确定这是否是你正在寻找真正的东西,但一个(有点没用的)为例,类似你写的示例代码的东西,会去是这样的:

class GetMethodTest { 
@Rule public JUnitRuleMockery context = new JunitRuleMockery(); 

@Test 
public void testGetMethod() throws Exception { 
    // Setup mocked object with expectations 
    final GetMethod method = context.mock(GetMethod.class); 
    context.checking(new Expectations() {{ 
     oneOf (method).getResponseBodyAsString(); 
     will(returnValue("Response text goes here")); 
    }}); 

    // Now do the checking against mocked object 
    String content = method.getResponseBodyAsString(); 
} 
} 
+0

在我的情况下不会真正起作用,请参阅我对hvgotcodes的评论。 – dcp 2010-10-04 18:43:48

+0

嗯,那么我可能会考虑使用像对象团队这样的Java扩展框架,它可以将特定的方法调用重新路由到您自己定义的方法,因此您可以利用您需要修改的控制流的精确点来进行注入无论是你自己的代码还是你的模拟对象。无论是公共方法还是私有方法都无关紧要,ObjecTeams充当Java的超集,因此您可以完成Java通常无法完成的任务。 – micdah 2010-10-04 22:23:09

4

看看jadler(http://jadler.net),这是一个我一直在研究的http stubbing/mocking库。 1.0.0稳定版已经刚刚发布,它应该提供您所需的功能:根据请求参数,头,等

@Test 
public void getAccount() { 

    onRequest() 
     .havingMethodEqualTo("GET") 
     .havingURIEqualTo("/accounts/1") 
     .havingBody(isEmptyOrNullString()) 
     .havingHeaderEqualTo("Accept", "application/json") 
    .respond() 
     .withTimeout(2, SECONDS) 
     .withStatus(200) 
     .withBody("{\"account\":{\"id\" : 1}}") 
     .withEncoding(Charset.forName("UTF-8")) 
     .withContentType("application/json; charset=UTF-8"); 

    final AccountService service = new AccountServiceRestImpl("http", "localhost", port()); 
    final Account account = service.getAccount(1); 

    assertThat(account, is(notNullValue())); 
    assertThat(account.getId(), is(1)); 
} 


@Test 
public void deleteAccount() { 

    onRequest() 
     .havingMethodEqualTo("DELETE") 
     .havingPathEqualTo("/accounts/1") 
    .respond() 
     .withStatus(204); 

    final AccountService service = new AccountServiceRestImpl("http", "localhost", port()); 
    service.deleteAccount(1); 

    verifyThatRequest() 
     .havingMethodEqualTo("DELETE") 
     .havingPathEqualTo("/accounts/1") 
    .receivedOnce(); 
}