2010-10-04 49 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(); 
}