kira_vdd
kira_vdd

Reputation: 23

How to unit test this function

I have a method. I want to test the method with a unit test. What's a good way to test that method?

public class ChoiceOption
    {
        public static int Choice(string message, string errorMessage)
        {
            while (true)
            {
                try
                {
                    Console.Write(message);
                    string userInput = Console.ReadLine();
                    if (userInput == string.Empty)
                    {
                        userInput = "0";
                    }
                    return int.Parse(userInput);
                }
                catch (Exception)
                {
                    Console.WriteLine(errorMessage);
                }
            }
        }
    }

Upvotes: 2

Views: 98

Answers (3)

David Ferenczy Rogožan
David Ferenczy Rogožan

Reputation: 25471

First, you should change the method to a pure function to make testing easier (e.g. no mocking, etc.), so you need to extract the user input outside the method and ideally also printing to the console. Now, you can emulate the user input from your test and also assert the exception:

public class ChoiceOption
{
    public static int Choice(string userInput, string message, string errorMessage)
    {
        if (userInput == string.Empty)
        {
            userInput = "0";
        }
        return int.Parse(userInput);
    }
}

Now, it's easily testable. The loop, the user input and catching of the exception(s) will be in the caller of this method. Which is your production code and also your unit test(s).

Upvotes: 1

Ian Mercer
Ian Mercer

Reputation: 39307

First of all, rewrite your method so it can be unit tested and doesn't rely on Console input and output, e.g.

public class ChoiceOption
{
    private readonly Func<string> readLine;
    private readonly Action<string> writeLine;

    public ChoiceOption(Func<string> readLine, Action<string> writeLine)
    {
        this.readLine = readLine;
        this.writeLine = writeLine;
    }

    public int Choice(string message, string errorMessage)
    {
        while (true)
        {
            writeLine(message);
            string userInput = readLine();
            if (string.IsNullOrEmpty(userInput)) return 0;
            if (int.TryParse(userInput, out int result))
            {
                return result;
            }
            writeLine(errorMessage);
        }
    }
}

Now you can inject methods for read and writeline that inject test data and collect the output to check it. Take a look at the nuget package Moq also as way to create those mock objects for testing.

[TestFixture]
public class TestMethod
{
    [TestCase("", ExpectedResult = "Message\n0")]
    [TestCase("123", ExpectedResult = "Message\n123")]
    [TestCase("A\n1234", ExpectedResult = "Message\nError\nMessage\n1234")]
    public string MethodReturnsExpected(string input)
    {
        // Create mock objects for testing that simulate user input
        int readPos = 0;
        string output = "";
        Func<string> readline = () => input.Split('\n')[readPos++];
        Action<string> writeline = (line) => output = output + line + "\n";

        // Create the 'unit under test'
        var uut = new ChoiceOption(readline, writeline);

        int result = uut.Choice("Message", "Error");

        // Return something that can be verified
        return output + result;
    }
}

Upvotes: 2

c4llmeco4ch
c4llmeco4ch

Reputation: 311

The first things you should cover are the expected, "correct" cases. In this case, that would be a few numbers (probably 0, a positive number, and a negative number).

At that point, you then try edge cases:

  • "hello"

  • 'c'

  • 2.5

  • 2^63

  • true

  • " "

Those are immediate examples I can think of, but ultimately your unit test is as strong as you are creative

Upvotes: 0

Related Questions