P
P
PJeys2021-06-01 15:45:18
Command line
PJeys, 2021-06-01 15:45:18

How to write a unit test for keyboard input?

using System;
using System.Threading;
using System.Collections.Generic;

public class EventLoop
{
    private ManualResetEventSlim _messageEvent = new ManualResetEventSlim(false);
    private Queue<Int32> _messageQueue = new Queue<Int32>();
    public int sum = 0;
    public void Threadmain()
    {
        var thrd = new Thread(PumpMessage);
        thrd.Start();
        WriteLine("Enter first number to summarize, enter q or Q to stop");
        while (true)
        {
            var message = WaitMessage();
            sum += message;
            WriteLine("Current sum:" + Convert.ToString(sum));
            if (Convert.ToString(message) == "q" || Convert.ToString(message) == "Q")
            {
                WriteLine("The final sum is" + Convert.ToString(sum));
                break;
            }

        }

    }
    private int WaitMessage()
    {
        _messageEvent.Wait();
        var message = _messageQueue.Dequeue();
        _messageEvent.Reset();
        return Convert.ToInt32(message);
    }
    private void PumpMessage()
    {
        while (true)
        {
            var num = ReadLine();
            if (num == "q" || num == "Q")
            {
                WriteLine("The final sum is" + Convert.ToString(sum));
                break;
            }
            _messageQueue.Enqueue(Convert.ToInt32(num));
            _messageEvent.Set();
        }
    }
    public virtual string ReadLine()
    {
        return Console.ReadLine();
    }
    public virtual void WriteLine(string strline)
    {
        Console.WriteLine(strline);
    }
}
public class Program
{
    static void Main(string[] args)
    {
        EventLoop obj = new EventLoop();
        obj.Threadmain();
    }
}

There is such program to which it is necessary to issue unit tests. The catch is that the user enters data for the program from the keyboard, how can you simulate input for successful testing?

Answer the question

In order to leave comments, you need to log in

3 answer(s)
Алексей Березников, 2021-06-05
@PJeys

Если вы действительно хотите тестировать ввод с клавиатуры, это значит что вам нужно замокать статический метод.
У Fody есть add-in Fody.Ionad, который позволяет делать как раз именно это.
Но, конечно, будет правильнее воспользоваться советом предыдущих ответчиков, и переделать код так, чтобы он был более тестируем.

C
cicatrix, 2021-06-01
@cicatrix

Пример, когда платят за строку кода :)
Код абсолютно НЕ тестопригодный, вы постарались.
На ввод с клавиатуры юнит-тест не нужен. Нужен юнит-тест на метод, который производит с этим вводом какие-либо действия. Основная логика у вас происходит именно в Threadmain() - методе, который ничего не принимает и ничего не возвращает, кроме возможных исключений.
1. Зачем ввод с клавиатуры в отдельном потоке, да ещё и с очередью, если ReadLine() блокирующий метод.
2. Convert.ToInt32() выдаст исключение, если аргументом будет строка, не содержащая цифры.
3. num == "q" || num == "Q" - есть методы .ToLower(), ToUpper(). Название переменной num абсолютно нелогично, если оно не числовое.
4. Ещё тестом надо покрыть PumpMessage(), чтобы проверить, выходит ли программа из цикла
UPD: Вот рефактор, который делает более-менее то же самое, и его можно тестировать:

using System;
using System.Linq;
using System.Collections.Generic;

class Program {

  static List<int> _numbers = new List<int>();  
  static void Main() {
    while(UserInput(Console.ReadLine()));
    Console.WriteLine($"Sum is: {CalcSum(_numbers)}");
  }
  
  static bool UserInput(string input)
  {
      if(string.IsNullOrEmpty(input)) return false;
      if(!int.TryParse(input, out int number)) return false;
      _numbers.Add(number);
      return true;
  }
  
  static int CalcSum(IEnumerable<int> numbers)
  {
      return numbers.Sum();
  }
}

Тесты для UserInput
UserInput получает на вход null и должен вернуть false
UserInput получает на вход "" и должен вернуть false
UserInput получает на вход что угодно, кроме числа и должен вернуть false
UserInput на вход число и возвращает true
Тесты для CalcSum
Получает на вход пустой список и возвращает 0
Получает на вход массив [1, 2] возвращает 3
(ну для пущей надёжности можно ещё добавить проверку входящего аргумента на null) и проверить, выбрасывается ли исключение

Роман, 2021-06-02
@yarosroman Куратор тега C#

Unit тесты, судя из названия, предназначены для тестирования функциональности модулей и отдельных методов, ни одним unittest фреймворком вы не провернете это, а у вас получается интеграционный тест. Пишем еще одно приложение, которое будет перехватывать ввод/вывод с консоли и тестировать ваше приложение. Вот для примера
https://www.codeproject.com/Questions/720259/How-t...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question