Question

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?

Was it helpful?

Solution

You could use expect.

OTHER TIPS

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.

Mock the input.

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

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.

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

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();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top