1

関数の単体テストの方法がわかりません。ユーザーが入力したものの代わりにアスタリスクが表示されるように、ユーザー入力のパスワード スタイルを取得するために使用されます。そのため、コンソール I/O をキャプチャして、期待値と比較しようとしています。

これは機能です:

public string getMaskedInput(string prompt)
{
    string pwd = "";
    ConsoleKeyInfo key;
    do
    {
        key = Console.ReadKey(true);
        if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
        {
            pwd = pwd += key.KeyChar;
            Console.Write("*");
        }
        else
        {
            if (key.Key == ConsoleKey.Backspace && pwd.Length > 0)
            {
                pwd = pwd.Substring(0, pwd.Length - 1);
                Console.Write("\b \b");
            }
        }

    }
    while (key.Key != ConsoleKey.Enter);
    return pwd;
}

そしてテスト:

public void getInputTest()
{
    //arrange
    var sr = new StringReader("a secret");
    var sw = new StringWriter();
    Console.SetOut(sw);
    Console.SetIn(sr);
    Input i = new Input();
    string prompt="what are you typing? ";

    //act
    string result = i.getMaskedInput(prompt);         

    //assert
    var writeResult = sw.ToString();
    Assert.IsTrue((writeResult == "what are you typing? ")&&(result=="a secret"));

編集: 単体テストを再確認したところ、バグがありました。修正したので、テストがハングします。テストをステップ実行すると、 と関係があることが示されますがConsole.ReadKey()、これはリダイレクトできないと思われStreamReader()ますReadLine()

また、これは同じテストで 2 つのアサートのようですが、この関数をテストする正しい方法ですか?

4

2 に答える 2

7

そのような動作を単体テストするべきではありません。このコードは、コンソールからの外部データに大きく依存しています。

しかし、これをテストすることを余儀なくされた場合...

まず、コンソールへの依存を断ち切ります。Console.Read や Console.Write などのコンソール操作を何らかのクラスでラップします。

public class ConsoleWrapper : IConsoleWrapper
{
    public ConsoleKeyInfo ReadKey()
    {
        return Console.ReadKey(true);
    }

    public void Write(string data)
    {
        Console.Write(data);
    }
}

また、インターフェイス IConsoleWrapper があります

public interface IConsoleWrapper
{
    ConsoleKeyInfo ReadKey();
    void Write(string data);
}

今あなたの機能であなたができること

    public static string GetMaskedInput(string prompt, IConsoleWrapper console)
    {
        string pwd = "";
        ConsoleKeyInfo key;
        do
        {
            key = console.ReadKey();
            if (key.Key != ConsoleKey.Backspace && key.Key != ConsoleKey.Enter)
            {
                pwd += key.KeyChar;
                console.Write("*");
            }
            else
            {
                if (key.Key == ConsoleKey.Backspace && pwd.Length > 0)
                {
                    pwd = pwd.Substring(0, pwd.Length - 1);
                    console.Write("\b \b");
                }
            }
        }
        while (key.Key != ConsoleKey.Enter);
        return pwd;
    }
}

このインターフェイスを使用すると、モックを作成して、呼び出されたメソッドとそのパラメーターを簡単に確認できます。また、操作全体をシミュレートできる内部文字列を持つ ConsoleStub を作成することもできます。

このようなもの。

public class ConsoleWrapperStub : IConsoleWrapper
{
    private IList<ConsoleKey> keyCollection;
    private int keyIndex = 0;

    public ConsoleWrapperStub(IList<ConsoleKey> keyCollection)
    {
        this.keyCollection = keyCollection;
    }

    public string Output = string.Empty;

    public ConsoleKeyInfo ReadKey()
    {
        var result = keyCollection[this.keyIndex];
        keyIndex++;
        return new ConsoleKeyInfo( (char)result ,result ,false ,false ,false);
    }

    public void Write(string data)
    {
        Output += data;
    }
}

このスタブを使用すると、独自の包含テスト シナリオを作成できます。

例えば

    [Test]
    public void If_Enter_first_then_return_empty_pwd()
    {
        // Arrange
        var stub = new ConsoleWrapperStub(new List<ConsoleKey> { ConsoleKey.Enter });
        var expectedResult = String.Empty;
        var expectedConsoleOutput = String.Empty;

        // Act

        var actualResult = Program.GetMaskedInput(string.Empty, stub);

        //     
        Assert.That(actualResult, Is.EqualTo(expectedResult));
        Assert.That(stub.Output, Is.EqualTo(expectedConsoleOutput));
    }

    [Test]
    public void If_two_chars_return_pass_and_output_coded_pass()
    {
        // Arrange
        var stub = new ConsoleWrapperStub(new List<ConsoleKey> { ConsoleKey.A, ConsoleKey.B, ConsoleKey.Enter });
        var expectedResult = "AB";
        var expectedConsoleOutput = "**";

        // Act

        var actualResult = Program.GetMaskedInput(string.Empty, stub);

        //     
        Assert.That(actualResult, Is.EqualTo(expectedResult));
        Assert.That(stub.Output, Is.EqualTo(expectedConsoleOutput));
    }

うまくいけば、これはあなたを助け、あなたは一般的なアイデアを得る:)

編集

わかりました、サンプルを編集し、動作する Nunit でテストしました。ただし、各テスト シナリオは ENTER キーで終了する必要があることを覚えておく必要があります。これがないと、while ループは無限になり、例外 KeynotFound が発生します。これは、リスト内の文字セットが限られているためです。

于 2012-12-20T08:28:30.157 に答える