2013-07-26 64 views
4

我在這個小問題上摸不着頭腦。如何對無效輸入進行單元測試「console.readLine」?

我有此線和3對其它類似的那些方法中的

try 
{ 
    int PhoneIMEINumber = int.Parse(Console.ReadLine()); 
} 

{ 
catch(Exception) 
{ 
    return null; 
} 

如果用戶輸入「ABCD」輸入,這會引發異常,我可以抓住它,並顯示一個錯誤消息。

但是我該如何做一個單元測試呢?我無法模擬單元測試的控制檯輸入,我想從單元測試中檢查是否返回null。

謝謝

+5

您可能不應該單元測試控制檯,而是測試業務規則。 – Romoku

+8

單元測試的一大優點是它可以讓你重新評估你的設計。你現在應該這樣做並重構你的代碼。目前,ReadLine與業務/驗證代碼緊密耦合。 –

+0

@HenkHolterman漢克,我有一個場景,我想測試一個方法,分析我的計算機上的文件,這是由用戶通過'Console.ReadLine()'指定的。這應如何處理? – alex

回答

5

就像發表的兩條評論。我會考慮重構你的代碼看起來更像

string input = Console.ReadLine(); 

try 
{ 
    int PhoneIMEINumber = parse_input(input); 
} 
catch(Exception) 
{ 
    return null; 
} 

,然後你就會有一個功能

public int parse_input(string input) 
{ 
    return int.Parse(input); 
} 

,那麼你會寫的parse_input功能的單元測試。雖然示例代碼看起來相當平凡,但很難證明圍繞int.Parse()的包裝函數編寫單元測試是正確的,但我假設將來您的解析可能會變得更加複雜。

+0

超級...這很簡單...正是我需要+1 –

+0

+1,因爲您實際上是唯一一個將業務邏輯與基礎架構分開的人。當驗證IMEI號碼時,所有其他答案只是試圖抽象出控制檯,因爲它與真正無關。 – jgauffin

+0

@jgauffin那麼OP特意問了如何單元測試'控制檯',儘管我更喜歡這種方法。 – Romoku

6

您可以設置Console.In使用SetIn給定的文本閱讀器:

var sr = new StringReader("Invalid int"); 
Console.SetIn(sr); 

int? parsed = MethodUnderTest(); 
Assert.IsNull(parsed); 
+0

這也是我首先想到的。我很困惑爲什麼這個答案有這麼幾個upvotes?這不行嗎? – mafu

+0

我正在爲使用控制檯的hello-world應用編寫測試用例,這正是我想要的。例如:輸入您的姓名驗證是否返回「您好」。謝謝。 –

+0

使用Console.SetIn是最實際的答案。您可以模擬傳遞的TextReader並驗證ReadLine調用計數。 –

7

如果你想單元測試Console,那麼你可能需要創建一個包裝接口。

public interface IConsole 
{ 
    string ReadLine(); 
} 

public class ConsoleWrapper : IConsole 
{ 
    public string ReadLine() 
    { 
     return Console.ReadLine(); 
    } 
} 

這樣您就可以創建一個存根/假來測試您的業務規則。

public class TestableConsole : IConsole 
{ 
    private readonly string _output; 

    public TestableConsole(string output) 
    { 
     _output = output; 
    } 

    public string ReadLine() 
    { 
     return _output; 
    } 
} 

測試內部:

public class TestClass 
{ 
    private readonly IConsole _console; 

    public TestClass(IConsole console) 
    { 
     _console = console; 
    } 

    public void RunBusinessRules() 
    { 
     int value; 
     if(!int.TryParse(_console.ReadLine(), out value) 
     { 
      throw new ArgumentException("User input was not valid"); 
     } 
    } 
} 

[Test] 
public void TestGettingInput() 
{ 
    var console = new TestableConsole("abc"); 

    var classObject = new TestClass(console); 

    Assert.Throws<ArgumentException>(() => classObject.RunBusinessRules()); 
} 

我會試圖避免單元測試Console,並承擔它的依賴性去。

+1

++經典依賴注入 –

+0

謝謝...非常詳細的答案,超!! +1。 Al W的解決方案更適合我的解決方案。 –

+0

是的,我不會推薦使用這個解決方案,除非你有特定的需求。 – Romoku

0

要單元測試代碼,那段代碼需要可測試。

要單元測試一個方法,我們做的是傳入一些已知的輸入,並檢查它是否返回預期的結果,或者如果我們有正確的副作用。

現在,如果你直接在你的方法中輸入內容,它不是很好的測試。它有兩個部分,讀取輸入和處理它。如果測試中的斷言失敗,則不知道哪一步失敗。單元測試應該旨在測試一個單元或一個代碼的單一責任。

要使其可測試,請讀取main方法中的輸入並將其傳遞給另一個處理方法(也是面向對象編程的常見概念),然後使用已知參數測試第二個方法。

相關問題