How to unit test a console input class?

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

I am considering using google-test for my unit testing, which makes it easier to automate all tests. However, I'm not sure how I can automate the console input testing.

Is there a way to simulate user input on the keyboard? Or do I have to manually enter my test input? Or perhaps a redirect stdin

(either to code or to a pipe when running a unit test)?

EDIT: I am planning on using GNU readline for user input. At the moment, I see no way to redirect the input stream of this library - maybe someone has some experience?

+2


source to share


7 replies


You can use expect .



+2


source


Basically, your class should be able to use a random input stream, not just stdin (and you should refactor it if it fails already).



After that, you can simply add a dummy stream with your custom data and simulate any user input.

+3


source


Discard the input.

+1


source


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

+1


source


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

Create an abstract class with members that match the readline functionality you want to use. The program is against this abstract class, not directly against the readline API. Use dependency injection to get an instance of this class in the code it needs.

Then you can create two implementations of this class, one that simply wraps the readline library and another mock implementation that you can use in your unit tests. The mock implementation will have additional elements that make it easier to simulate the user.

+1


source


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

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 like:

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

      

0


source


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

Using a wrapper and interface for all third-party controls that participate in unit tests makes it easier to work with an isolation framework (such as Rhino Mocks). This gives me control over testing and explicitly defines dependencies in my code. Since I need new console features, I can just add them to the wrapper interface. I haven't had any issues with UI 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's 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();
}

      

0


source







All Articles