Метод тестирования калькулятора

#c# #unit-testing #testing #uwp

#c# #модульное тестирование #тестирование #uwp

Вопрос:

У меня есть этот калькулятор, который я сделал в UWP. Он может складывать, умножать, вычитать, делать деления, преобразовывать градусы Цельсия в градусы Фаренгейта и наоборот.

Моя проблема в том, что мне нужен способ его тестирования, чтобы я мог добавлять, вычитать, делить, умножать в одном методе тестирования. А также протестируйте, чтобы я мог взять значение Цельсия и преобразовать его в градусы Фаренгейта, и все это в тестовом методе.

Я могу изменить его так, чтобы некоторые из моих методов стали общедоступными, а не частными, но я не знаю, как мне следует протестировать некоторые из них?

Мои методы тестирования находятся в верхней части кода.

 using NUnit.Framework;
using System;
using System.Data;
using System.Reflection;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;


// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352amp;clcid=0x409

namespace Calc
{
    /// <summary>
    /// A calculator, namespace start. 
    /// </summary>
    /// 

    
    /// Public start, mainpage. 
    public sealed partial class MainPage : Page
    {


       
        /// Input for Celcius/Farh.
        string input;


        /// <summary>
        /// Testing celcius / F.
        /// </summary>
        [TestMethod]
         private void TestDifferentScales()
          {
          
          }


        /// <summary>
        /// Test method - testing all functions regarding mathematical equations!
        /// </summary>
        [TestMethod()]
        public void AdditionTest()
        {
            
           
            
        }




        /// <summary>
        /// Start main program!
        /// </summary>
        public MainPage()
        {
            //Startar allt.
            this.InitializeComponent();
        }


        /// <summary>
        /// Button for number 1.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {

            textBox.Text  = '1';
            input  = "1";
          
        }

        /// <summary>
        /// Button for number 2.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '2';
            input  = "2";

        }


        /// <summary>
        /// Button for number 3.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '3';
            input  = "3";
        }


        /// <summary>
        /// Button for number 4.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '4';
            input  = "4";

        }


        /// <summary>
        /// Button for number 5.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '5';
            input  = "5";
        }



        /// <summary>
        /// Button for number 6.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_5(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '6';
            input  = "6";

        }



        /// <summary>
        /// Button for number 7.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_6(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '7';
            input  = "7";

        }



        /// <summary>
        /// Button for number 8.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_7(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '8';
            input  = "8";
        }



        /// <summary>
        /// Button for number 9.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_8(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '9';
            input  = "9";

        }



        /// <summary>
        /// Button for numbers 42 "Marcus".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_9(object sender, RoutedEventArgs e)
        {
            textBox.Text  = "42";
            input  = "42";
        }



        /// <summary>
        /// Button for number 0.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_10(object sender, RoutedEventArgs e)
        {
            textBox.Text  = '0';
            input  = "0";
        }



        /// <summary>
        /// Button for multiplication of equation "F = M*A".
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_11(object sender, RoutedEventArgs e)
        {

            /* F = M * A 
             * Denna ekvation är simpel och man lär sig den redan i början utav Fysik 1.
             * Ekvationen är inte specifik, så som tex "F = M * G" då gravitationen kan bli ett "fixed" värde som 
             * går mellan 9,802 och 9,820.
             * Anledningen till varför denna är så simpel är för att jag ville bevisa att det gick att ha många komplikaitoner 
             * i ett knapp tryck. Så denna skulle lika gärna kunnat vara knappen för multiplikation.
             */
            textBox.Text  = '*';

        }



        /// <summary>
        /// Button for addition.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickPlus(object sender, RoutedEventArgs e)
        {

            /* "Exceptions without Execeptions"
             * Här försökte jag att gå runt utan att behöva använda en 
             * try/catch eller Exception inför min "data table" på min "=" knapp.
             * Men, som sagt, det är ingen skillnad här och på min knapp för "F = M * A".
             * Det finns ju klara skillander, jag har försökt att se till så att jag går tillbaka ett
             * steg ifall det finns flera matematiska karaktärer. 
             * 
             * MEN: Det skapar problem då jag fortfarande ville kunna köra "6--1 = 7" utan att krasha allt.
             * 
             */
            var last = textBox.Text;
            if (last[last.Length - 1] != ' ' || last[last.Length - 1] != '-' || last[last.Length - 1] != '*' || last[last.Length - 1] != '/')
            {
                textBox.Text  = ' ';
            }
            else
            {
                textBox.Text = last.Remove(last.Length - 1, 1);
                textBox.Text  = ' ';
            }
        }


        /// <summary>
        /// Button for subtraction. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickMinus(object sender, RoutedEventArgs e)
        {
            var last = textBox.Text;
            if (last[last.Length - 1] != ' ' || last[last.Length - 1] != '-' || last[last.Length - 1] != '*' || last[last.Length - 1] != '/')
            {
                textBox.Text  = '-';
            }
            else
            {
                textBox.Text = last.Remove(last.Length - 1, 1);
                textBox.Text  = '-';
            }
        }



        /// <summary>
        /// Button for multiplication.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickTimes(object sender, RoutedEventArgs e)
        {
            var last = textBox.Text;
            if (last[last.Length - 1] != ' ' || last[last.Length - 1] != '-' || last[last.Length - 1] != '*' || last[last.Length - 1] != '/')
            {
                textBox.Text  = '*';
            }
            else
            {
                textBox.Text = last.Remove(last.Length - 1, 1);
                textBox.Text  = '*';
            }
        }
        

        /// <summary>
        /// Button for division. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickDEv(object sender, RoutedEventArgs e)
        {
            var last = textBox.Text;
            if (last[last.Length - 1] != ' ' || last[last.Length - 1] != '-' || last[last.Length - 1] != '*' || last[last.Length - 1] != '/')
            {
                textBox.Text  = '/';
            }
            else
            {
                textBox.Text = last.Remove(last.Length - 1, 1);
                textBox.Text  = '/';
            }
        }


        /// <summary>
        /// Button for "Equal", the equal button.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickEqual(object sender, RoutedEventArgs e)
        {
            /* Exception.
             * Jag prövade att unit testa här med en thread timer för att kunna 
             * skriva ett meddelande i boxen typ "Error: Please try again" 
             * och sen rensa allt, men det gav error, det funkade men jag ville
             * inte ha något error med så jag tog bort den från min "catch".
             * 
             */
            try
            {
             object q = new DataTable().Compute(textBox.Text, null);
                        textBox.Text = q.ToString();
            }
            catch
            {
             
                /*
                 * Här återställer jag bara allt.  
                 */
           
                textBox.Text = string.Empty;
                input = string.Empty;
            }
           
        }



        /// <summary>
        /// Button for reset of calcuator.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_ClickReset(object sender, RoutedEventArgs e)
        {

            /*
             * Åter ställer här på "ClickReset" också.
             */
            textBox.Text = string.Empty;
            input = string.Empty;

        }

        /// <summary>
        /// Button from  F to C.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_fc_(object sender, RoutedEventArgs e)
        {

            /*
             * Här så var jag tvungen att gå fram och tillbaka med att 
             * konvertera saker från och till int och string. 
             * Multiplicerade och addade 32 eller tog bort 32 för att
             * få rätt värden i slutet. 
             */
            int value = int.Parse(input);
            int after = value - 32; 
            int a = (int)(decimal.Divide(after, (decimal)1.8));
            string answer = a.ToString();
            textBox.Text = string.Empty;
            textBox.Text = answer;
        }


        /// <summary>
        /// Button from C to F.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void Button_Click_cf_(object sender, RoutedEventArgs e)
        {
            int value = int.Parse(input);
            int a = (int)(decimal.Multiply(value, (decimal)1.8)   32);
            string answer = a.ToString();
            textBox.Text = string.Empty;
            textBox.Text = answer; 
        }
    }
}
 

Комментарии:

1. В общем, ваши тесты должны быть в другом проекте модульного тестирования. Для лучшей тестируемости вы хотите абстрагировать всю логику калькулятора в другой класс, где основная функциональность будет представлена в виде общедоступных методов, которые вы можете тестировать независимо от пользовательского интерфейса.

2. Проверьте шаблон MVVM, тогда тестирование должно быть простым 🙂

3.См. Калькулятор с WPF (обзор кода).

4. Я могу дать вам исчерпывающий метод, с помощью которого вы комбинируете умножение, деление, сложение, вычитание и скобки, но вам нужно кое-что знать о преобразовании инфиксных выражений в постфиксные. Конечно, это очень просто

5. @meysamasadi Это было бы неплохо!

Ответ №1:

Позвольте мне привести вам пример, который избавит вас от пользовательского ввода. Вам нужно разрешить только определенные символы на входе. Если вы знаете о преобразовании инфиксных выражений в постфиксные, понимание примера будет отличным.

И вы создаете самый продвинутый калькулятор с наименьшим количеством кода.

Входные фразы не должны содержать пробела, в этом случае удалите пробелы.

Шаг 1. В следующих строках показано, как использовать

 //real example in world
string infix = "(((13 26)*12)-15 15*(20/6))";
List<string> arrayPostfix;
            
if (ValidBraces(infix))
{
    convertToPostfixArray(ref infix, out arrayPostfix);
    double result = calculate(arrayPostfix);
    Console.WriteLine(result);
}
else
    Console.WriteLine("invalid experssion***********************");
 

Шаг 2. Метод проверки правильности фигурных скобок

 static bool ValidBraces(string infix)
{
   bool valid = true;
   int i = 0;
   Stack<char> symbls = new Stack<char>();

   while (i < infix.Length)
   {
       if (infix[i] == '(')
           symbls.Push(infix[i]);

       if (infix[i] == ')')
           if (symbls.Count == 0)
           {
              valid = false;
              break;
           }
           else
           {
               char ch = symbls.Pop();
               if (ch != '(')
               {
                  valid = false;
                  break;
               }
           }

           i  ;
   }

   if (symbls.Count > 0)
       valid = false;

   return valid;
}
 

Шаг 3. Способ преобразования инфиксных выражений в постфиксные

 static bool convertToPostfixArray(ref string infix, out List<string> postfix)
{
    int prio = 0;
    postfix = new List<string>();
    Stack<Char> s1 = new Stack<char>();
    string value = "";
    for (int i = 0; i < infix.Length; i  )
    {
        char ch = infix[i];
        if (ch == '(')
        {  
           s1.Push(ch);                     
        }
        else if (ch == ')')
        {
           if (!string.IsNullOrEmpty(value))
           {
               postfix.Add(value);
               value = string.Empty;
           }
           while (s1.Peek() != '(')
           {
               postfix.Add(s1.Pop().ToString());
           }
           s1.Pop();
        }
        else if (ch == ' ' || ch == '-' || ch == '*' || ch == '/')
        {
            if (!string.IsNullOrEmpty(value))
            {
                postfix.Add(value);
                value = string.Empty;
            }
            if (s1.Count <= 0)
            {
                s1.Push(ch);
            }
            else
            {
                if (s1.Peek() == '*' || s1.Peek() == '/')
                    prio = 1;
                else
                    prio = 0;
                if (prio == 1)
                {
                   char c = s1.Peek();
                   if (c != '(')
                       postfix.Add(s1.Pop().ToString());
                   i--;
                }
                else
                {
                    if (ch == ' ' || ch == '-')
                    {
                        char c = s1.Peek();
                        if (c != '(')
                          postfix.Add(s1.Pop().ToString());
                        s1.Push(ch);
                    }
                    else
                       s1.Push(ch);
                }
            }
        }
        else
        {
            value  = ch.ToString();
        }
    }

    if (!string.IsNullOrEmpty(value))
    {
        postfix.Add(value);
        value = string.Empty;
    }

    int len = s1.Count;
    for (int j = 0; j < len; j  )
    {
       char c = s1.Pop();
       if (c != '(')
          postfix.Add(c.ToString());
    }
    return true;
}
 

Шаг 4. Метод вычисления Postfix

 static double calculate(List<string> postfix)
{
   Stack<double> stack = new Stack<double>();
   foreach (string item in postfix)
   {
       double answer = 0;
       if (item == " " || item == "-" || item == "*" || item == "/")
       {
          char charVal = System.Convert.ToChar(item);
          double operand1 = ((Double)stack.Pop());
          double operand2 = ((Double)stack.Pop());

          answer = Solve(charVal, operand1, operand2);
          stack.Push((answer));
       }
       else
       {
           stack.Push(Convert.ToDouble(item));
       }
   }
   return stack.Pop();
}
public static double Solve(char operation, double operand1, double operand2)
{
    double answer = 0;
    switch (operation)
    {
        case ' ':
          answer = operand1   operand2;
          break;
        case '-':
          answer = operand2 - operand1;
          break;
        case '*':
          answer = operand1 * operand2;
          break;
        case '/':
          answer = operand2 / operand1;
          break;
    }
    return answer;
}