4

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

我正在考虑使用google-test框架进行单元测试,这使得自动化所有测试变得容易。但是,我不确定如何自动测试控制台输入。

有什么方法可以模拟键盘上的用户输入吗?还是我必须手动输入我的测试输入?或者可能重定向stdin(在运行单元测试时在代码中或通过管道)?

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

4

7 回答 7

3

你可以使用期望

于 2009-08-21T01:55:20.063 回答
3

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

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

于 2009-08-21T01:55:21.170 回答
1

如果您的平台是 .NET,这是一种方法

于 2009-08-21T07:13:18.530 回答
1

模拟输入。

于 2009-08-21T01:50:37.383 回答
1

我计划使用 GNU readline 进行用户输入。目前我看不到任何方法来重定向这个库的输入流

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

然后你可以创建这个类的两个实现:一个简单地包装 readline 库,另一个模拟实现,你可以在单元测试中使用它。模拟实现将具有额外的成员,可以轻松模拟用户。

于 2009-08-21T09:14:34.073 回答
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() {}
}
于 2009-08-21T07:33:41.157 回答
0

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

为单元测试中涉及的所有 3rd 方控件使用包装器和接口使得使用隔离框架(如 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();
}
于 2009-08-21T15:14:54.473 回答