簡體   English   中英

如何為使用網絡連接的類編寫jUnit測試

[英]How to write a jUnit test for a class that uses a network connection

我想知道使用jUnit測試在下面的類中測試方法“pushEvent()”的最佳方法是什么。 我的問題是,私有方法“callWebsite()”總是需要連接到網絡。 我怎樣才能避免這個要求或重構我的課程,我可以在沒有連接到網絡的情況下測試它?

class MyClass {

    public String pushEvent (Event event) {
        //do something here
        String url = constructURL (event); //construct the website url
        String response = callWebsite (url);

        return response;
    }

    private String callWebsite (String url) {
        try {
            URL requestURL = new URL (url);
            HttpURLConnection connection = null;
            connection = (HttpURLConnection) requestURL.openConnection ();


            String responseMessage = responseParser.getResponseMessage (connection);
            return responseMessage;
        } catch (MalformedURLException e) {
            e.printStackTrace ();
            return e.getMessage ();
        } catch (IOException e) {
            e.printStackTrace ();
            return e.getMessage ();
        }
    }

}

打樁

您需要一個測試雙(存根)以允許隔離,簡單,單元測試。 以下是未經測試,但演示了這個想法。 使用依賴注入將允許您在測試時注入HttpURLConnection的測試版本。

public class MyClass() 
{
   private IHttpURLConnection httpUrlConnection;   

   public MyClass(IHttpURLConnection httpUrlConnection)
   {
       this.httpUrlConnection = httpUrlConnection;
   }

   public String pushEvent(Event event) 
   {
       String url = constructURL(event);
       String response = callWebsite(url);
       return response;
  }
}

然后,您創建一個存根(有時稱為模擬對象)作為具體實例的替代。

class TestHttpURLConnection : IHttpURLConnection { /* Methods */ }

您還將構建一個具體版本,供您的生產代碼使用。

class MyHttpURLConnection : IHttpURLConnection { /* Methods */ }

使用您的測試類( 適配器 ),您可以指定測試期間應該發生的事情。 模擬框架將使您能夠使用更少的代碼執行此操作,或者您可以手動連接它。 測試的最終結果是,您將設置對測試的期望,例如,在這種情況下,您可以將OpenConnection設置為返回一個真正的布爾值(順便說一下,這只是一個例子)。 然后,您的測試將斷言當此值為true時,PushEvent方法的返回值與某些預期結果匹配。 我暫時沒有正確地觸及Java,但是這里有一些建議的模擬框架 ,由StackOverflow成員指定。

可能的解決方案:您可以擴展此類,覆蓋callWebsite(您必須為此目的保護它) - 並且覆蓋方法編寫一些存根方法實現。

從略微不同的角度接近事物......

我不太擔心測試這個特定的課程。 其中的代碼非常簡單,雖然確保使用連接的功能測試會有所幫助,但單元級測試“可能”不是必需的。

相反,我專注於測試它所調用的實際上做某事的方法。 特別...

我從這一行測試了constructURL方法:

String url = constructURL (event);

確保它可以從不同的事件正確構造一個URL,並在它應該的時候拋出異常(可能是在一個無效的事件或null)。

我將從以下行測試該方法:

String responseMessage = responseParser.getResponseMessage (connection);

可能將任何“從連接中獲取信息”邏輯拉出到一個proc中,並且只留下“解析所述信息”的原始信息:

String responseMessage = responseParser.getResponseMessage(responseParser.getResponseFromConnection(connection));

或類似的規定。

想法是在一個方法中放置任何“必須處理外部數據源”代碼,並且在可以輕松測試的單獨方法中放置任何代碼邏輯。

作為Finglas關於模擬的有用答案的替代方案,考慮一種我們覆蓋callWebsite()功能的存根方法。 在我們對callWebsite的邏輯不像pushEvent()中調用的其他邏輯那樣感興趣的情況下,這非常有效。 要檢查的一件重要事情是使用正確的URL調用callWebsite。 所以,首先改變的是callWebsite()的方法簽名變為:

protected String callWebsite(String url){...}

現在我們創建一個這樣的存根類:

class MyClassStub extends MyClass {
    private String callWebsiteUrl;
    public static final String RESPONSE = "Response from callWebsite()";

    protected String callWebsite(String url) {
        //don't actually call the website, just hold onto the url it was going to use
        callWebsiteUrl = url;
        return RESPONSE;
    }
    public String getCallWebsiteUrl() { 
        return callWebsiteUrl; 
    }
}

最后在我們的JUnit測試中:

public class MyClassTest extends TestCase {
    private MyClass classUnderTest;
    protected void setUp() {
        classUnderTest = new MyClassStub();
    }
    public void testPushEvent() { //could do with a more descriptive name
        //create some Event object 'event' here
        String response = classUnderTest.pushEvent(event);
        //possibly have other assertions here
        assertEquals("http://some.url", 
                     (MyClassStub)classUnderTest.getCallWebsiteUrl());
        //finally, check that the response from the callWebsite() hasn't been 
        //modified before being returned back from pushEvent()
        assertEquals(MyClassStub.RESPONSE, response);
    }
 }

創建一個抽象類WebsiteCaller ,它將是ConcreteWebsiteCallerWebsiteCallerStub的父級。

這個類應該有一個方法callWebsite (String url) 將您的callWebsite方法從MyClass移動到ConcreteWebsiteCaller MyClass看起來像:

class MyClass {

    private WebsiteCaller caller;

    public MyClass (WebsiteCaller caller) {
        this.caller = caller;
    }

    public String pushEvent (Event event) {
        //do something here
        String url = constructURL (event); //construct the website url
        String response = caller.callWebsite (url);

        return response;
    }
}

並以適合測試的某種方式在您的WebsiteCallerStub中實現方法callWebsite

然后在你的單元測試中做這樣的事情:

@Test
public void testPushEvent() {
   MyClass mc = new MyClass (new WebsiteCallerStub());
   mc.pushEvent (new Event(...));
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM