如何对依赖于 Console 的 switch 语句进行单元测试 [英] How to unit test a switch statement with a dependency on Console

查看:46
本文介绍了如何对依赖于 Console 的 switch 语句进行单元测试的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是单元测试的新手,我使用的是 VS 2010 单元测试框架.

I'm brand new to unit testing, and I'm using the VS 2010 unit testing framework.

我有一个函数可以从用户那里获取一个整数,然后根据用户输入执行不同的函数.我已经阅读了很多关于单元测试的内容,但我还没有找到任何可以告诉我如何测试 switch 语句的每个分支的内容.到目前为止我得到了什么:

I've got a function that grabs an integer from the user, then executes different functions based on user input. I've read a lot on unit testing but I haven't found anything that shows me how to test each branch of a switch statement. What I've got so far:

    [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));
            }
        }
    }

当 case 1 下的函数被调用时,首先发生的是字符串Enter Account Number:"被写入控制台.然而,这根本行不通.我没有正确地将输入传递给控制台吗?感谢您的帮助!

When the function under case 1 gets called, the first thing that happens is the string "Enter Account Number: " gets written to the console. However, this isn't working at all. Am I not passing input to the console correctly? Thanks for the help!

我的 RunBankApplication() 函数:

my RunBankApplication() function:

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);

推荐答案

我想你的 RunBankApplication 看起来像这样:

I suppose your RunBankApplication looks similar to this:

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 的固定依赖,这会使您的方法无法测试,您应该在构造函数中注入此依赖.

To get read of your fixed dependency on Console which makes your method untestable you should inject this dependency in constructor.

您需要一个定义依赖项的接口:

You need an interface defining your dependency:

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

您为其创建一个默认实现:

You create a default implementation for it:

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

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

然后将这个实现注入到 BankManager 类中并在类中使用它:

You then inject this implementation in your BankManager class and use it inside the class:

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 是此类模拟库的不错选择:

Now you can mock this dependency in your tests. Moq is good choice of such a mocking library:

[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 容器 在应用程序中自动注入您的依赖项.

Sure, this is an overkill for such a simple example, but the approach is really useful in larger projects. As a next step you can then use an IoC container to automatically inject your dependency in the application.

这篇关于如何对依赖于 Console 的 switch 语句进行单元测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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