C# unit test for a method which calls Console.ReadLine()

Solution 1:

You'll need to refactor the lines of code that call Console.ReadLine into a separate object, so you can stub it out with your own implementation in your tests.

As a quick example, you could just make a class like so:

public class ConsoleNameRetriever {
     public virtual string GetNextName()
     {
         return Console.ReadLine();
     }
}

Then, in your method, refactor it to take an instance of this class instead. However, at test time, you could override this with a test implementation:

public class TestNameRetriever : ConsoleNameRetriever {
     // This should give you the idea...
     private string[] names = new string[] { "Foo", "Foo2", ... };
     private int index = 0;
     public override string GetNextName()
     {
         return names[index++];
     }
}

When you test, swap out the implementation with a test implementation.

Granted, I'd personally use a framework to make this easier, and use a clean interface instead of these implementations, but hopefully the above is enough to give you the right idea...

Solution 2:

You should refactor your code to remove the dependency on the console from this code.

For instance, you could do this:

public interface IConsole
{
    void Write(string message);
    void WriteLine(string message);
    string ReadLine();
}

and then change your code like this:

public void SignInScoreBoard(int steps, IConsole console)
{
    ... just replace all references to Console with console
}

To run it in production, pass it an instance of this class:

public class ConsoleWrapper : IConsole
{
    public void Write(string message)
    {
        Console.Write(message);
    }

    public void WriteLine(string message)
    {
        Console.WriteLine(message);
    }

    public string ReadLine()
    {
        return Console.ReadLine();
    }
}

However, at test-time, use this:

public class ConsoleWrapper : IConsole
{
    public List<String> LinesToRead = new List<String>();

    public void Write(string message)
    {
    }

    public void WriteLine(string message)
    {
    }

    public string ReadLine()
    {
        string result = LinesToRead[0];
        LinesToRead.RemoveAt(0);
        return result;
    }
}

This makes your code easier to test.

Of course, if you want to check that the correct output is written as well, you need to add code to the write methods to gather the output, so that you can assert on it in your test code.

Solution 3:

You can use Moles to replace Console.ReadLine with your own method without having to change your code at all (designing and implementing an abstract console, with support for dependency injection is all completely unnecessary).

Solution 4:

Why not create a new stream (file/memory) for both stdin and stdout, then redirect input/ouput to your new streams before calling the method? You could then check the content of the streams after the method has finished.