2012-11-15 83 views
1

我是單元測試的新手,我正在使用VS 2010單元測試框架。如何在控制檯上依賴於單元測試switch語句

我有一個從用戶抓取整數的函數,然後根據用戶輸入執行不同的函數。我已經閱讀了很多關於單元測試的內容,但是我還沒有發現任何能夠告訴我如何測試switch語句的每個分支的東西。到目前爲止,我已經得到了什麼:

[TestMethod] 
    public void RunBankApplication_Case1() 
    { 
     using (var sw = new StringWriter()) 
     { 
      using (var sr = new StringReader("1")) 
      { 
       Console.SetOut(sw); 
       Console.SetIn(sr); 
       BankManager newB = new BankManager(); 
       newB.RunBankApplication(); 
       var result = sw.ToString(); 

       string expected = "Enter Account Number: "; 
       Assert.IsTrue(result.Contains(expected)); 
      } 
     } 
    } 

當在案例1中函數被調用,這種情況發生的第一件事是字符串「中輸入賬號:」被寫入到控制檯。 但是,這根本不起作用。我沒有正確地將輸入傳遞給控制檯嗎? 感謝您的幫助!

編輯:我RunBankApplication()函數:

do 
     { 
      DisplayMenu(); 

      option = GetMenuOption(); 

      switch (option) 
      { 
       case 1: 
        if (!CreateAccount()) 
        { 
         Console.WriteLine("WARNING: Could not create account!"); 
        } 
        break; 
       case 2: 
        if (!DeleteAccount()) 
        { 
         Console.WriteLine("WARNING: Could not delete account!"); 
        } 

        break; 
       case 3: 
        if (!UpdateAccount()) 
        { 
         Console.WriteLine("WARNING: Could not update account!"); 
        } 

        break; 
       case 4: DisplayAccount(); 
        break; 
       case 5: status = false; 
        break; 
       default: Console.WriteLine("ERROR: Invalid choice!"); 
        break; 
      } 
     } while (status); 
+1

理想情況下,您可以將應用程序設置爲使用依賴注入,以便您可以使用模擬來表示依賴關係。 –

回答

3

我想你RunBankApplication類似於此:

public void RunBankApplication() 
{ 
    var input = Console.ReadLine(); 
    switch (input) 
    { 
     case "1": 
      Console.WriteLine("Enter Account Number: "); 
      break; 
     case "2": 
      Console.WriteLine("Hello World!"); 
      break; 
     default: 
      break; 
    } 
} 

要讀取您的固定依賴關係Console,這使得您的方法無法測試,您應該在構造函數中注入此依賴項。

你需要定義你所依賴的接口:

public interface IConsoleService 
{ 
    string ReadLine(); 
    void WriteLine(string message); 
} 

您創建一個默認的實現它:

public class ConsoleService : IConsoleService 
{ 
    public string ReadLine() 
    { 
     return Console.ReadLine(); 
    } 

    public void WriteLine(string message) 
    { 
     Console.WriteLine(message); 
    } 
} 

你再注入這個實現在BankManager類,並用它裏面的類:

public class BankManager 
{ 
    private IConsoleService _consoleService; 

    public BankManager(IConsoleService consoleService) 
    { 
     _consoleService = consoleService; 
    } 

    public void RunBankApplication() 
    { 
     var input = _consoleService.ReadLine(); 
     switch (input) 
     { 
      case "1": 
       _consoleService.WriteLine("Enter Account Number: "); 
       break; 
      case "2": 
       _consoleService.WriteLine("Hello World!"); 
       break; 
      default: 
       break; 
     } 
    } 
} 

現在你可以嘲笑這個依賴在你的測試中。 Moq是這樣的嘲弄庫的好選擇:

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void GetMessage_Input1_ReturnEnterAccountNumberMessage() 
    { 
     var consoleService = new Mock<IConsoleService>(); 
     consoleService.Setup(c => c.ReadLine()).Returns("1"); 

     var bankManager = new BankManager(consoleService.Object); 
     bankManager.RunBankApplication(); 

     consoleService.Verify(c => c.WriteLine("Enter Account Number: "), Times.Once()); 
    } 

    [TestMethod] 
    public void GetMessage_Input2_ReturnHelloWorldMessage() 
    { 
     var consoleService = new Mock<IConsoleService>(); 
     consoleService.Setup(c => c.ReadLine()).Returns("2"); 

     var bankManager = new BankManager(consoleService.Object); 
     bankManager.RunBankApplication(); 

     consoleService.Verify(c => c.WriteLine("Hello World!"), Times.Once()); 
    } 
} 

當然,這是對於這樣一個簡單的例子是矯枉過正,但該方法是在大型項目非常有用。接下來,您可以使用IoC container自動在應用程序中注入依賴關係。

+0

這看起來不錯!我之前沒有使用Moq,但我會做一些閱讀。我唯一的問題是:如果我有一個函數獲取用戶輸入並返回該整數(我已更新我的操作以顯示我的函數RunBankApplication()的外觀。 – SantasNotReal

+0

@Brandon如果'GetMenuOption'處於相同的類它也可以與控制檯通信,而不是以同樣的方式進行測試,也就是說它應該使用控制檯抽象。更好的方法是在測試'RunBankApplication'時嘲笑該函數,並將它放在不同的類中會使這更容易。 –

2

不應該有自動化測試用戶輸入。你的測試需要提供參數,如果你依賴外部資源(WCF服務,數據庫,文件系統,用戶輸入等等),那麼你需要嘲笑它們。這就是像Moq這樣的測試框架爲你做的。

如果您想測試switch語句的每個case,那麼您需要對每個case進行測試。

順便說一下,您無法使用控制檯,因爲您的單元測試可能位於類庫中,而不是控制檯應用程序。

1

這是不正確的做法。在單元測試中不應該與控制檯通信。只需提取可與輸入參數配合使用的函數並測試此函數。

這樣的:

在YourExtractedClass:

 public string GetMessage(string input) 
     { 
      var result = string.Empty; 

      switch (input) 
      { 
       case "1": 
        result = "Enter Account Number: "; 
        break; 
       case "2": 
        result = "Hello World!"; 
        break; 
       default: 
        break; 
      } 

      return result; 
     } 

....

在您的測試類YourExtractedClass

[Test] 
    public void GetMessage_Input1_ReturnEnterAccountNumberMessage() 
    { 
     var result = GetMessage("1"); 
     var expected = "Enter Account Number: "; 

     Assert.That(result == expected); 
    } 

    [Test] 
    public void GetMessage_Input2_ReturnHelloWorldMessage() 
    { 
     var result = GetMessage("1"); 
     var expected = "Hello World!"; 

     Assert.That(result == expected); 
    } 

還有一兩件事:這是更好地把你的字符串(「輸入帳號」等)移到一個地方(例如一些Consta nts類)。不要重複自己!

瞭解單元測試的好書:

The Art of Unit Testing: With Examples in .Net

Pragmatic Unit Testing in C# with NUnit, 2nd Edition

xUnit Test Patterns: Refactoring Test Code

+0

不幸的是,我正在使用的任何函數中只有2個需要任何輸入參數(不包括構造函數),否則這將是單元測試的好方法。 – SantasNotReal

+0

@Brandon剛剛閱讀「單元測試的藝術」 - 你會發現很多有關單元測試的有趣信息。 –