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

发布于 2024-08-02 09:55:16 字数 380 浏览 4 评论 0原文

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

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

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

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

In one of my applications I have a class which is responsible for user input. The default method of input is the console (keyboard), and I want to write some unit tests for it to make sure it is correct.

I am considering using the google-test framework for my unit testing, which makes it easy to automate all the testing. However, I am not sure how I can automate testing of the console input.

Is there any way to simulate user input on the keyboard? Or do I have to manually enter my test input? Or perhaps redirect stdin (either in code or by a pipe when running the unit test)?

EDIT: I am planning on using GNU readline for user input. At the moment I can't see any way to redirect the input stream of this library - perhaps someone else has experience with this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

花心好男孩 2024-08-09 09:55:16

您可以使用expect

You could use expect.

ぃ双果 2024-08-09 09:55:16

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

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

Basically, your class should be able to use random input stream, not only stdin (and you have to refactor it, if it's unable yet).

After that you'll be able to simply put a mock stream with your custom data and to simulate any user input.

养猫人 2024-08-09 09:55:16

模拟输入。

Mock the input.

小…楫夜泊 2024-08-09 09:55:16

如果您的平台是 .NET,这是一种方法< /a>.

If your platform is .NET, here's one way to do it.

终止放荡 2024-08-09 09:55:16

我计划使用 GNU readline
用于用户输入。此刻我不能
查看重定向输入的任何方法
该库的流

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

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

I am planning on using GNU readline
for user input. At the moment I can't
see any way to redirect the input
stream of this library

Create an abstract class with members that match the readline functionality that you want to use. Program against this abstract class instead of directly against the readline API. Use dependency injection to get an instance of this class to the code that needs it.

Then you can create two implementations of this class: one which simply wraps the readline library, and another mock implementation which you can use in your unit tests. The mock implementation would have extra members that make it easy to simulate a user.

玩心态 2024-08-09 09:55:16

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

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() {}
}

For .NET/C# you could use the Options class or variations found in this question. Because you have all commands mapped to delegates, you can then unit test each of the methods at the end of the delegates, and easily find unknown commands:

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

The MyHandler class would be similar to:

public class MyHandler
{
    public void Show() { }
    public void Connect(string[] args){}
    public void Dir() {}
}
抚你发端 2024-08-09 09:55:16

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

对单元测试中涉及的所有第 3 方控件使用包装器和接口使得使用隔离框架(如 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();
}

For the console, I always just wrap it with my own implementation.

Using a wrapper and interface for all 3rd party controls that are involved in unit tests makes working with an isolation framework (like Rhino Mocks) super easy. It gives me control over testing, and explicitly defines the dependancies in my code. As I need new features of the console I can just add them to the wrappers interface. I have not had issues with interface bloat yet...

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

Here is a test in action

[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();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文