1

私は単体テストの初心者で、VS 2010 単体テスト フレームワークを使用しています。

ユーザーから整数を取得し、ユーザー入力に基づいてさまざまな関数を実行する関数があります。単体テストについて多くのことを読みましたが、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 の関数が呼び出されると、最初に文字列 "Enter Account Number: " がコンソールに書き込まれます。ただし、これはまったく機能していません。入力をコンソールに正しく渡していませんか? 助けてくれてありがとう!

編集: 私の 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);
4

3 に答える 3

4

あなたの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 コンテナーを使用して、依存関係をアプリケーションに自動的に注入できます。

于 2012-11-15T20:52:51.943 に答える
2

自動テストでは、ユーザー入力があってはなりません。テストはパラメーターを提供する必要があり、外部リソース (WCF サービス、データベース、ファイル システム、ユーザー入力など) に依存している場合は、それらをモックする必要があります。これは、Moqのようなテスト フレームワークが行うことです。

switch ステートメントの各ケースをテストする場合は、各ケースのテストが必要です。

ところで、単体テストはおそらくコンソール アプリではなくクラス ライブラリにあるため、コンソールを使用することはできません。

于 2012-11-15T20:12:29.667 に答える
1

it's not right approach. You shouldn't communicate with Console in unit tests. Just extract your function which works with input parameters and test this function.

like this:

in 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;
        }

....

In your Test class for 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);
    }

And one more thing: it's better to move you strings ("Enter Account Number" etc) to one place (fro example to some Constants class). Don't repeat yourself!

read good books about unit testing:

The Art of Unit Testing: With Examples in .Net

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

xUnit Test Patterns: Refactoring Test Code

于 2012-11-15T20:12:34.673 に答える