Задать вопрос
@PJeys

Как написать юнит тест для ввода с клавиатуры?

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

Имеется такая программа, к которой нужно оформить юнит тесты. Загвоздка в том, что данные для программы пользователь вводит с клавиатуры, как можно имитировать ввод для успешного тестирования?
  • Вопрос задан
  • 1543 просмотра
Подписаться 1 Простой Комментировать
Решения вопроса 1
gdt
@gdt
Программист
Если вы действительно хотите тестировать ввод с клавиатуры, это значит что вам нужно замокать статический метод.
У Fody есть add-in Fody.Ionad, который позволяет делать как раз именно это.
Но, конечно, будет правильнее воспользоваться советом предыдущих ответчиков, и переделать код так, чтобы он был более тестируем.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@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) и проверить, выбрасывается ли исключение
Ответ написан
yarosroman
@yarosroman Куратор тега C#
C# the best
Unit тесты, судя из названия, предназначены для тестирования функциональности модулей и отдельных методов, ни одним unittest фреймворком вы не провернете это, а у вас получается интеграционный тест. Пишем еще одно приложение, которое будет перехватывать ввод/вывод с консоли и тестировать ваше приложение. Вот для примера

https://www.codeproject.com/Questions/720259/How-t...
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы