如何对需要用户输入C#的代码进行单元测试 [英] How to unit test code that requires user input c#

查看:63
本文介绍了如何对需要用户输入C#的代码进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我第一次进行单元测试/集成测试,我有一个问题.因此,我开始对代码进行单元测试,但是我有一个方法,它实际上是整个应用程序的逻辑,其中调用了多个方法,并且需要用户输入.如何测试该方法?方法如下:

its my first time doing unit tests/integration tests and I have a question. So I started doing unit tests for my code, but I have a method, which is actually the logic of the whole application, where multiple methods are called, and user input is required. How can I test that method? Here is the method:

  public async Task RunAsync()
    {
      
        var watch = System.Diagnostics.Stopwatch.StartNew();
        var playAgain = 'y';

        do
        {
            var attempts = 1;
            var foundNumber = false;
            while (attempts < 10 && foundNumber == false)
            {
                try
                {
                    var inputNumber = int.Parse(GetInput());

                    if (inputNumber == _randomNumber)
                    {
                        foundNumber = true;
                        OnSuccesfulGuess(watch, attempts);

                    }
                    else if (attempts < 10)
                    {
                        OnWrongGuessWithinAttempts(inputNumber);
                    }
                    else
                    {
                        Console.WriteLine("Oops, maybe next time.");                      
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Please enter a number");
                }

                attempts++;
            }

            playAgain = PlayAgain(playAgain);
            _randomNumber = await GetRandomNumber(1, 100);
            Log.Information("User wants to play again");
        }
        while (playAgain == 'y' || playAgain == 'Y');
    }

这是我在Program类中运行以启动应用程序的方法.

This is the method where i run in my Program class in order to start the application.

推荐答案

您的代码本质上是不可测试的.

Your code is essentially untestable.

该方法执行了太多工作.应该将其拆分为几个可以分别测试的较小的文件.

The method does too much work. It should be splitted into several smaller ones that can be tested separately.

您应该摆脱静态方法.因为你不能让他们假的.

You should get rid of static methods. Because you can't get them fake.

应该通过网络(我看到使用WebSocket)以及从数据库或文件系统中获取数据.您应该将现成的数据传递给此方法.

Getting data over the network (I see using WebSocket), as well as from the database or file system, should be brought out. You should pass ready-made data to this method.

这是修改后的代码,分为小方法.从代码中删除了日志和事件,以免使解释复杂化.

Here is the modified code, broken down into small methods. Logging and events are removed from the code so as not to complicate the explanation.

public class App
{
    private readonly Random _random = new Random();

    private Task<int> GetRandomNumber(int min, int max)
    {
        return Task.FromResult(_random.Next(min, max));
    }

    internal int GetInput()
    {
        Console.WriteLine("Please guess a number between 1 and 100");
        int value;

        while (true)
        {
            string input = Console.ReadLine();
            bool result = int.TryParse(input, out value);

            if (!result)
                Console.WriteLine("Not a number");
            else if (value < 1 || value > 100)
                Console.WriteLine("Must be between 1 and 100");
            else
                break;
        }
        return value;
    }

    internal bool PlayAgain()
    {
        Console.WriteLine("Do you want to play again?");
        string input = Console.ReadLine();
        return input == "Y" || input == "y";
    }

    internal void Guessing(int randomNumber)
    {
        int attempts = 1;
        while (attempts < 10)
        {
            var inputNumber = GetInput();
            // logging
            if (inputNumber == randomNumber)
            {
                // OnSuccesfulGuess
                return;
            }
            else
            {
                // OnWrongGuessWithinAttempts
            }
            attempts++;
        }
        Console.WriteLine("Oops, maybe next time.");
        // logging
    }

    public async Task RunAsync()
    {
        do
        {
            int randomNumber = await GetRandomNumber(1, 100);
            Guessing(randomNumber);
        }
        while (PlayAgain());
    }
}

现在,我们可以测试各个方法了.
我使用MSTest.

Now we have the ability to test individual methods.
I use MSTest.

[DataTestMethod]
[DataRow("Y")]
[DataRow("y")]
public void PlayAgain_InputY_ReturnsTrue(string value)
{
    using (var reader = new StringReader(value))
    {
        Console.SetIn(reader);
        var app = new App();

        bool result = app.PlayAgain();

        Assert.IsTrue(result);
    }
}

[DataTestMethod]
[DataRow("N")]
[DataRow("boo")]
[DataRow("")]
public void PlayAgain_InputNotY_ReturnsFalse(string value)
{
    using (var reader = new StringReader(value))
    {
        Console.SetIn(reader);
        var app = new App();

        bool result = app.PlayAgain();

        Assert.IsFalse(result);
    }
}

我们对其他方法也做同样的事情.

We do the same with the other methods.

这是GetInput方法的测试.

由于输入错误的值时,内部循环会无限期地运行,因此我们必须通过输入正确的值来中断它.这是通过换行符传递两个值来完成的:"0\n50".输入错误的值是对输出字符串的测试,然后使用正确的值中断循环.

Since there is a loop inside that runs indefinitely when incorrect values are entered, we must interrupt it by entering the correct value. This is done by passing two values via a line feed: "0\n50". Entering an incorrect value is a test of the output string, then interrupting the loop with the correct value.

[DataTestMethod]
[DataRow("1")]
[DataRow("50")]
[DataRow("100")]
public void GetInput_InputCorrectString_ReturnsNumber(string value)
{
    using (var reader = new StringReader(value))
    {
        Console.SetIn(reader);
        var app = new App();

        int actual = app.GetInput();
        int expected = int.Parse(value);

        Assert.AreEqual(expected, actual);
    }
}

[DataTestMethod]
[DataRow("0\n50")]
[DataRow("101\n50")]
public void GetInput_InputSmallerOrGreaterValue_WritesMessage(string value)
{
    using (var reader = new StringReader(value))
    using (var writer = new StringWriter())
    {
        Console.SetIn(reader);
        Console.SetOut(writer);
        var app = new App();

        _ = app.GetInput();

        string actualMessage = writer.ToString();
        string expectedMessage = "Must be between 1 and 100";

        Assert.IsTrue(actualMessage.Contains(expectedMessage));
    }
}

[DataTestMethod]
[DataRow("x\n50")]
[DataRow("qwerty\n50")]
public void GetInput_InputNotNumber_WritesMessage(string value)
{
    using (var reader = new StringReader(value))
    using (var writer = new StringWriter())
    {
        Console.SetIn(reader);
        Console.SetOut(writer);
        var app = new App();

        _ = app.GetInput();

        string actualMessage = writer.ToString();
        string expectedMessage = "Not a number";

        Assert.IsTrue(actualMessage.Contains(expectedMessage));
    }
}

这篇关于如何对需要用户输入C#的代码进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆