如何对控制台输入类进行单元测试?

时间:2009-08-21 01:02:49

标签: c++ unit-testing user-input googletest

在我的一个应用程序中,我有一个负责用户输入的类。输入的默认方法是控制台(键盘),我想为它编写一些单元测试以确保它是正确的。

我正在考虑使用google-test框架进行单元测试,这样可以轻松实现所有测试的自动化。但是,我不确定如何自动测试控制台输入。

有没有办法模拟键盘上的用户输入?或者我是否必须手动输入我的测试输入?或者可能重定向stdin(在运行单元测试时代码或管道)?

编辑:我打算使用GNU readline进行用户输入。目前我看不到任何方法来重定向此库的输入流 - 也许其他人有这方面的经验?

7 个答案:

答案 0 :(得分:3)

您可以使用expect

答案 1 :(得分:3)

基本上,你的类应该能够使用随机输入流,而不仅仅是stdin(你必须重构它,如果它还没有)。

之后,您将能够简单地将模拟流与您的自定义数据放在一起,并模拟任何用户输入。

答案 2 :(得分:1)

模拟输入。

答案 3 :(得分:1)

如果您的平台是.NET,here's one way to do it

答案 4 :(得分:1)

  

我打算使用GNU readline   用于用户输入。目前我做不到   看到任何重定向输入的方法   这个图书馆的流

创建一个抽象类,其成员与您要使用的readline功能相匹配。针对此抽象类而不是直接针对readline API进行编程。使用dependency injection将此类的实例获取到需要它的代码。

然后,您可以创建此类的两个实现:一个简单地包装readline库,另一个模拟实现可以在单元测试中使用。模拟实现将有额外的成员,可以很容易地模拟用户。

答案 5 :(得分:0)

对于.NET / C#,您可以使用此问题中的Options类或变体。因为您将所有命令映射到委托,然后您可以在委托结束时对每个方法进行单元测试,并轻松找到未知命令:

MyHandler handler = new MyHandler()
CommandOptions options = new CommandOptions();

// Put this in the test Setup
options.Add("show", handler.Show)
        .Add("connect", v => handler.Connect(v))
        .Add("dir", handler.Dir);

if (!options.Parse(args))
   Assert.Fail(string.Format("{0} was not recognised.",args))

MyHandler类类似于:

public class MyHandler
{
    public void Show() { }
    public void Connect(string[] args){}
    public void Dir() {}
}

答案 6 :(得分:0)

对于控制台,我总是用自己的实现来包装它。

对单元测试中涉及的所有第三方控件使用包装器和接口,使得使用隔离框架(如Rhino Mocks)非常容易。它让我可以控制测试,并在我的代码中明确定义了依赖性。由于我需要控制台的新功能,我可以将它们添加到包装器界面。我还没有接口膨胀的问题......

public interface IConsoleShim
{
    void WriteLine(string message);
    ConsoleKeyInfo ReadKey();
}
public class ConsoleShim : IConsoleShim
{
    public void WriteLine(string message)
    {
        Console.WriteLine(message);
    }
    public ConsoleKeyInfo ReadKey()
    {
        return Console.ReadKey();
    }
}

这是一个实际的测试

[NUnit.Framework.Test]
public void Run_writes_to_console_100_times_waits_for_keypress()
{
    // arrange
    Rhino.Mocks.MockRepository mocks = new Rhino.Mocks.MockRepository();
    IConsoleShim consoleMock = mocks.StrictMock<IConsoleShim>();
    Program program = new Program(consoleMock);
    int expected = 100;

    // VerifyAll automatically called
    Rhino.Mocks.With.Mocks(mocks).Expecting(() =>
        {
            Rhino.Mocks.Expect.Call(() => consoleMock.WriteLine("")).IgnoreArguments().Repeat.Times(expected);
            Rhino.Mocks.Expect.Call(consoleMock.ReadKey()).Return(new ConsoleKeyInfo());
        });

    //act
    program.Run();
}