paint-brush
यूनिट टेस्ट के साथ .NET C# कंसोल एप्लिकेशन को पूरी तरह से कवर करनाद्वारा@ahmedtarekhasan
2,848 रीडिंग
2,848 रीडिंग

यूनिट टेस्ट के साथ .NET C# कंसोल एप्लिकेशन को पूरी तरह से कवर करना

द्वारा Ahmed Tarek Hasan26m2023/01/06
Read on Terminal Reader

बहुत लंबा; पढ़ने के लिए

कुछ सहकर्मी शिकायत कर रहे हैं कि कभी-कभी वे कुछ मॉड्यूल या एप्लिकेशन के लिए टीडीडी लागू करने या यूनिट परीक्षण लिखने में सक्षम नहीं होते हैं। कंसोल एप्लिकेशन इनमें से एक है। जब इनपुट कुंजी स्ट्रोक द्वारा पास किया जाता है और आउटपुट स्क्रीन पर प्रस्तुत किया जाता है तो मैं कंसोल एप्लिकेशन का परीक्षण कैसे कर सकता हूं? !! आपको "कंसोल" एप्लिकेशन का परीक्षण करने की आवश्यकता नहीं है, आप इसके पीछे व्यावसायिक तर्क का परीक्षण करना चाहते हैं।
featured image - यूनिट टेस्ट के साथ .NET C# कंसोल एप्लिकेशन को पूरी तरह से कवर करना
Ahmed Tarek Hasan HackerNoon profile picture

टेस्ट ड्रिवेन डेवलपमेंट (TDD), डिपेंडेंसी इंजेक्शन (DI), इनवर्जन ऑफ कंट्रोल (IoC), और IoC कंटेनरों का उपयोग करके 100% कवरेज प्राप्त करने के लिए सर्वोत्तम अभ्यास।


मेरे कुछ सहकर्मी शिकायत कर रहे हैं कि कभी-कभी वे कुछ मॉड्यूल या एप्लिकेशन के लिए टीडीडी लागू करने या यूनिट परीक्षण लिखने में सक्षम नहीं होते हैं, कंसोल एप्लिकेशन इनमें से एक हैं।


जब इनपुट कीस्ट्रोक्स द्वारा पारित किया जाता है और आउटपुट स्क्रीन पर प्रस्तुत किया जाता है तो मैं कंसोल एप्लिकेशन का परीक्षण कैसे कर सकता हूं? !!


दरअसल, यह समय-समय पर होता है, आप पाते हैं कि आप किसी ऐसी चीज के लिए यूनिट टेस्ट लिखने की कोशिश कर रहे हैं जिस पर आपका कोई नियंत्रण नहीं है।


अनस्प्लैश पर संगगा रीमा रोमन सेलिया द्वारा फोटो

ग़लतफ़हमी

सच तो यह है, तुम बस बिंदु चूक गए। आपको "कंसोल" एप्लिकेशन का परीक्षण करने की आवश्यकता नहीं है, आप इसके पीछे व्यावसायिक तर्क का परीक्षण करना चाहते हैं।


जब आप एक कंसोल एप्लिकेशन का निर्माण कर रहे होते हैं, तो आप किसी के उपयोग के लिए एक एप्लिकेशन बना रहे होते हैं, वह कुछ इनपुट पास करने और कुछ संबंधित आउटपुट प्राप्त करने की अपेक्षा करता है, और यही आपको वास्तव में परीक्षण करने की आवश्यकता होती है


आप System.Console स्टैटिक क्लास का परीक्षण नहीं करना चाहते हैं, यह एक बिल्ट-इन क्लास है जो .NET फ्रेमवर्क में शामिल है और आपको इस पर Microsoft पर भरोसा करना होगा।


अब, आपको यह सोचने की आवश्यकता है कि इन दो क्षेत्रों को अलग-अलग घटकों या मॉड्यूल में कैसे अलग किया जाए ताकि आप अपनी इच्छा के लिए दूसरे के साथ हस्तक्षेप किए बिना परीक्षण लिखना शुरू कर सकें, और यही वह है जो मैं आपको समझाने जा रहा हूं ...


अनस्प्लैश पर मार्क फ्लेचर-ब्राउन द्वारा फोटो

विचार

सबसे पहले, आइए एक बेवकूफ सरल कंसोल एप्लिकेशन विचार के साथ आएं और इसे लागू करने के लिए एक उदाहरण के रूप में उपयोग करें।


सबसे पहले, आपके पास यह सरल मेनू है।


छवि अहमद तारेक द्वारा


जब आप विकल्प 1 चुनते हैं और अपना नाम दर्ज करते हैं, तो आपको नीचे दी गई छवि के अनुसार हैलो संदेश मिलता है। एंटर मारने से एप्लिकेशन बंद हो जाएगा।


छवि अहमद तारेक द्वारा


जब आप विकल्प 2 चुनते हैं और अपना नाम दर्ज करते हैं, तो आपको नीचे दी गई छवि के अनुसार अलविदा संदेश मिलता है। एंटर मारने से एप्लिकेशन बंद हो जाएगा।


छवि अहमद तारेक द्वारा


बहुत सरल, है ना? हां, मैं आपसे सहमत हूं। हालाँकि, मान लेते हैं कि UI, तार, वर्ण और स्क्रीन पर जो कुछ भी आप देखते हैं, वह आवश्यकताओं का हिस्सा है।


इसका मतलब यह है कि यदि आप यूनिट परीक्षण लिखने जा रहे हैं, तो इसे इस तरह से भी कवर किया जाना चाहिए कि उत्पादन कोड में एक वर्ण पर मामूली परिवर्तन, असफल इकाई परीक्षण को ट्रिगर करे।


अनस्प्लैश पर ब्रेट जॉर्डन द्वारा फोटो

योजना

यह हमारी योजना है:

  1. कंसोल एप्लिकेशन को पारंपरिक खराब तरीके से बनाएं।
  2. देखें कि हम स्वचालित इकाई परीक्षण लिख सकते हैं या नहीं।
  3. कंसोल एप्लिकेशन को अच्छे तरीके से पुन: कार्यान्वित करें।
  4. कुछ इकाई परीक्षण लिखिए।

अनस्प्लैश पर मेहदी द्वारा फोटो

बुरा तरीका

बस, सब कुछ एक ही स्थान पर करें।


 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace MyConsoleApp { class Program { static void Main(string[] args) { var input = string.Empty; do { Console.WriteLine("Welcome to my console app"); Console.WriteLine("[1] Say Hello?"); Console.WriteLine("[2] Say Goodbye?"); Console.WriteLine(""); Console.Write("Please enter a valid choice: "); input = Console.ReadLine(); if (input == "1" || input == "2") { Console.Write("Please enter your name: "); string name = Console.ReadLine(); if (input == "1") { Console.WriteLine("Hello " + name); } else { Console.WriteLine("Goodbye " + name); } Console.WriteLine(""); Console.Write("Press any key to exit... "); Console.ReadKey(); } else { Console.Clear(); } } while (input != "1" && input != "2"); } } }


हम यहाँ क्या देख सकते हैं:

  1. सब कुछ एक ही स्थान पर है।
  2. हम सीधे स्थैतिक System.Console वर्ग का उपयोग कर रहे हैं।
  3. हम System.Console से टकराए बिना व्यावसायिक तर्क का परीक्षण नहीं कर सकते।

अनस्प्लैश पर ब्रेट जॉर्डन द्वारा फोटो

यूनिट टेस्ट लिखने की कोशिश कर रहा है

सचमुच? क्या आप वास्तव में उस कोड के लिए यूनिट टेस्ट लिखने में सक्षम होने की उम्मीद कर रहे हैं?

यहां चुनौतियां हैं:

  1. System.Console जैसे स्थिर वर्गों के आधार पर।
  2. निर्भरताओं को परिभाषित और अलग नहीं कर सकते।
  3. मोक्स या स्टब्स के साथ निर्भरताओं को प्रतिस्थापित नहीं कर सकता।

यदि आप इसके बारे में कुछ कर सकते हैं, तो आप एक नायक हैं...मेरा विश्वास करें।


Unsplash पर Volkan Olmez द्वारा फ़ोटो

अच्छा तरीका

अब, आइए अपने समाधान को छोटे-छोटे मॉड्यूल में विभाजित करें।


कंसोल प्रबंधक

यह वह मॉड्यूल है जो कंसोल ... किसी भी कंसोल से हमें आवश्यक कार्यक्षमता प्रदान करने के लिए ज़िम्मेदार है।


इस मॉड्यूल में दो भाग होंगे:

  1. सार।
  2. कार्यान्वयन।


इसलिए हमारे पास निम्नलिखित होंगे:

  1. IConsoleManager : यह इंटरफ़ेस परिभाषित करता है कि हम किसी कंसोल मैनेजर से क्या उम्मीद कर रहे हैं।
  2. ConsoleManagerBase : यह सार वर्ग है जो IConsoleManager को लागू करता है और सभी कंसोल प्रबंधकों के बीच कोई सामान्य कार्यान्वयन प्रदान करता है।
  3. ConsoleManager प्रबंधक: यह डिफ़ॉल्ट कंसोल प्रबंधक कार्यान्वयन है जो System.Console को लपेटता है और वास्तव में रनटाइम पर उपयोग किया जाता है।


 using System; namespace ConsoleManager { public interface IConsoleManager { void Write(string value); void WriteLine(string value); ConsoleKeyInfo ReadKey(); string ReadLine(); void Clear(); } }


 using System; namespace ConsoleManager { public abstract class ConsoleManagerBase : IConsoleManager { public abstract void Clear(); public abstract ConsoleKeyInfo ReadKey(); public abstract string ReadLine(); public abstract void Write(string value); public abstract void WriteLine(string value); } }


 using System; namespace ConsoleManager { public class ConsoleManager : ConsoleManagerBase { public override void Clear() { Console.Clear(); } public override ConsoleKeyInfo ReadKey() { return Console.ReadKey(); } public override string ReadLine() { return Console.ReadLine(); } public override void Write(string value) { Console.Write(value); } public override void WriteLine(string value) { Console.WriteLine(value); } } }


हम यहाँ क्या देख सकते हैं:

  1. अब हमारे पास IConsoleManager है।
  2. इकाई परीक्षण लिखते समय IConsoleManager को बदलने के लिए हम मोक्स और स्टब्स का उपयोग कर सकते हैं।
  3. सामान्य आधार वर्ग ConsoleManagerBase के लिए हम बच्चों द्वारा उपयोग किए जाने वाले किसी भी सामान्य कार्यान्वयन को प्रदान नहीं कर रहे हैं।
  4. मुझे पता है कि यह करने के लिए सबसे अच्छी बात नहीं है, हालांकि, मैं इसे यहां सिर्फ आपको याद दिलाने के लिए कर रहा हूं कि यह विकल्प मौजूद है और जब भी जरूरत हो आप इसका इस्तेमाल कर सकते हैं।

कार्यक्रम प्रबंधक

यह वह मॉड्यूल है जो मुख्य एप्लिकेशन कार्यक्षमता प्रदान करने के लिए ज़िम्मेदार है।


इस मॉड्यूल में दो भाग होंगे:

  1. सार।
  2. कार्यान्वयन।


इसलिए हमारे पास निम्नलिखित होंगे:

  1. IProgramManager : यह इंटरफ़ेस परिभाषित करता है कि हम किसी प्रोग्राम मैनेजर से क्या उम्मीद कर रहे हैं।
  2. ProgramManagerBase : यह अमूर्त वर्ग है जो IProgramManager को लागू करता है और सभी प्रोग्राम मैनेजरों के बीच कोई सामान्य कार्यान्वयन प्रदान करता है।
  3. ProgramManager : यह डिफ़ॉल्ट Program Manager कार्यान्वयन है जो वास्तव में रनटाइम पर उपयोग किया जाता है। यह IConsoleManager पर भी निर्भर करता है।


 namespace ProgramManager { public interface IProgramManager { void Run(); } }


 namespace ProgramManager { public abstract class ProgramManagerBase : IProgramManager { public abstract void Run(); } }


 using ConsoleManager; namespace ProgramManager { public class ProgramManager : ProgramManagerBase { private readonly IConsoleManager m_ConsoleManager; public ProgramManager(IConsoleManager consoleManager) { m_ConsoleManager = consoleManager; } public override void Run() { string input; do { m_ConsoleManager.WriteLine("Welcome to my console app"); m_ConsoleManager.WriteLine("[1] Say Hello?"); m_ConsoleManager.WriteLine("[2] Say Goodbye?"); m_ConsoleManager.WriteLine(""); m_ConsoleManager.Write("Please enter a valid choice: "); input = m_ConsoleManager.ReadLine(); if (input == "1" || input == "2") { m_ConsoleManager.Write("Please enter your name: "); var name = m_ConsoleManager.ReadLine(); if (input == "1") { m_ConsoleManager.WriteLine("Hello " + name); } else { m_ConsoleManager.WriteLine("Goodbye " + name); } m_ConsoleManager.WriteLine(""); m_ConsoleManager.Write("Press any key to exit... "); m_ConsoleManager.ReadKey(); } else { m_ConsoleManager.Clear(); } } while (input != "1" && input != "2" && input != "Exit"); } } }


हम यहाँ क्या देख सकते हैं:

  1. अब हमारे पास IConsoleManager की निर्भरता ProgramManager पर अच्छी तरह से परिभाषित है।
  2. हमारे पास IProgramManager है और हम इकाई परीक्षण लिखते समय IProgramManager को बदलने के लिए मॉक और स्टब्स का उपयोग कर सकते हैं।
  3. सामान्य आधार वर्ग ProgramManagerBase के लिए हम बच्चों द्वारा उपयोग किए जाने वाले किसी भी सामान्य कार्यान्वयन को प्रदान नहीं कर रहे हैं।
  4. मुझे पता है कि यह करने के लिए सबसे अच्छी बात नहीं है, हालांकि, मैं इसे यहां सिर्फ आपको याद दिलाने के लिए कर रहा हूं कि यह विकल्प मौजूद है और जब भी जरूरत हो आप इसका इस्तेमाल कर सकते हैं।


ProgramManager वर्ग को छोटे भागों में विभाजित किया जा सकता है। इससे यूनिट परीक्षणों को ट्रैक करना और कवर करना आसान हो जाएगा। हालाँकि, यह कुछ ऐसा है जिसे करने के लिए मैं आप पर छोड़ रहा हूँ।


सांत्वना आवेदन

यह मुख्य अनुप्रयोग है।


यहां हम प्रयोग करने जा रहे हैं निंजा हमारे आईओसी कंटेनर के रूप में। इसका उपयोग करना आसान है और आप हमेशा उनके ऑनलाइन दस्तावेज़ीकरण की जांच कर सकते हैं।


मुख्य कंसोल एप्लिकेशन प्रोजेक्ट पर, हम NinjectDependencyResolver.cs फ़ाइल बनाएंगे। यह फाइल इस प्रकार होगी।


 using Ninject.Modules; using ConsoleManager; using ProgramManager; namespace MyConsoleApp { public class NinjectDependencyResolver : NinjectModule { public override void Load() { Bind<IConsoleManager>().To<ConsoleManager.ConsoleManager>(); Bind<IProgramManager>().To<ProgramManager.ProgramManager>(); } } }


हम यहाँ क्या देख सकते हैं:

  1. NinjectDependencyResolver वर्ग NinjectModule को इनहेरिट कर रहा है।
  2. हम void Load() विधि को ओवरराइड कर रहे हैं जहां हम उम्मीद के मुताबिक अपनी बाइंडिंग सेट कर रहे हैं।


अब, Program.cs पर:


 using Ninject; using System.Reflection; using ProgramManager; namespace MyConsoleApp { class Program { private static IProgramManager m_ProgramManager = null; static void Main(string[] args) { var kernel = new StandardKernel(); kernel.Load(Assembly.GetExecutingAssembly()); m_ProgramManager = kernel.Get<IProgramManager>(); m_ProgramManager.Run(); } } }


हम यहाँ क्या देख सकते हैं:

  1. हम IProgramManager पर निर्भर हैं।
  2. हमने var kernel = new StandardKernel(); .
  3. फिर हमने कर्नेल के माध्यम से निर्भरता को kernel.Load(Assembly.GetExecutingAssembly()); . यह Ninject को वर्तमान असेंबली/प्रोजेक्ट के अंदर NinjectModule को इनहेरिट करने वाले सभी वर्गों से इसकी बाइंडिंग प्राप्त करने का निर्देश देता है।
  4. इसका मतलब यह है कि बाइंडिंग हमारे NinjectDependencyResolver वर्ग से आएगी क्योंकि यह NinjectModule को इनहेरिट कर रहा है और वर्तमान असेंबली/प्रोजेक्ट के अंदर स्थित है।
  5. IProgramManager का एक उदाहरण प्राप्त करने के लिए हम निम्नानुसार kernel.Get<IProgramManager>(); .


अब, देखते हैं कि इस क्षण तक हमने जो डिजाइन और काम किया है, उससे हमारी समस्या ठीक हो गई है या नहीं।


अनस्प्लैश पर मार्कस विंकलर द्वारा फोटो

सच्चाई का क्षण

तो, अब सवाल यह है कि क्या हम अपने कंसोल एप्लिकेशन को यूनिट परीक्षणों के साथ कवर कर सकते हैं? इस प्रश्न का उत्तर देने के लिए, आइए कुछ इकाई परीक्षण लिखने का प्रयास करें...


स्टब्स या मोक्स

यदि आपके पास यूनिट परीक्षण के साथ कुछ अनुभव है, तो आपको पता होना चाहिए कि हमारे पास निर्भरताओं को बदलने के लिए उपयोग किए जाने वाले स्टब्स और मोक्स हैं।


केवल मनोरंजन के लिए, मैं यहाँ हमारे उदाहरण के लिए स्टब्स का उपयोग करूँगा।


इसलिए, मैं ConsoleManagerStub को IConsoleManager मैनेजर के लिए एक स्टब के रूप में निम्नानुसार परिभाषित करता हूं:


 using System; using System.Collections.Generic; using System.Text; namespace ConsoleManager { public class ConsoleManagerStub : ConsoleManagerBase { private int m_CurrentOutputEntryNumber; private readonly List<string> m_Outputs = new List<string>(); public event Action<int> OutputsUpdated; public event Action OutputsCleared; public Queue<object> UserInputs { get; } = new Queue<object>(); public override void Clear() { m_CurrentOutputEntryNumber++; m_Outputs.Clear(); OnOutputsCleared(); OnOutputsUpdated(m_CurrentOutputEntryNumber); } public override ConsoleKeyInfo ReadKey() { ConsoleKeyInfo result; object input; if (UserInputs.Count > 0) { input = UserInputs.Dequeue(); } else { throw new ArgumentException("No input was presented when an input was expected"); } if (input is ConsoleKeyInfo key) { result = key; } else { throw new ArgumentException("Invalid input was presented when ConsoleKeyInfo was expected"); } return result; } public override string ReadLine() { object input; if (UserInputs.Count > 0) { input = UserInputs.Dequeue(); } else { throw new ArgumentException("No input was presented when an input was expected"); } string result; if (input is string str) { result = str; WriteLine(result); } else { throw new ArgumentException("Invalid input was presented when String was expected"); } return result; } public override void Write(string value) { m_Outputs.Add(value); m_CurrentOutputEntryNumber++; OnOutputsUpdated(m_CurrentOutputEntryNumber); } public override void WriteLine(string value) { m_Outputs.Add(value + "\r\n"); m_CurrentOutputEntryNumber++; OnOutputsUpdated(m_CurrentOutputEntryNumber); } protected void OnOutputsUpdated(int outputEntryNumber) { OutputsUpdated?.Invoke(outputEntryNumber); } protected void OnOutputsCleared() { OutputsCleared?.Invoke(); } public override string ToString() { var result = string.Empty; if (m_Outputs == null || m_Outputs.Count <= 0) return result; var builder = new StringBuilder(); foreach (var output in m_Outputs) { builder.Append(output); } result = builder.ToString(); return result; } } }


और अंत में, इकाई परीक्षण इस प्रकार होंगे:


 using ConsoleManager; using NUnit.Framework; using System; using System.Collections.Generic; namespace MyConsoleApp.Tests { [TestFixture] public class ProgramManagerTests { private ConsoleManagerStub m_ConsoleManager = null; private ProgramManager.ProgramManager m_ProgramManager = null; [SetUp] public void SetUp() { m_ConsoleManager = new ConsoleManagerStub(); m_ProgramManager = new ProgramManager.ProgramManager(m_ConsoleManager); } [TearDown] public void TearDown() { m_ProgramManager = null; m_ConsoleManager = null; } [TestCase("Ahmed")] [TestCase("")] [TestCase(" ")] public void RunWithInputAs1AndName(string name) { m_ConsoleManager.UserInputs.Enqueue("1"); m_ConsoleManager.UserInputs.Enqueue(name); m_ConsoleManager.UserInputs.Enqueue(new ConsoleKeyInfo()); var expectedOutput = new List<string> { "Welcome to my console app\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: ", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\nPlease enter your name: ", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\nPlease enter your name: " + name + "\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\nPlease enter your name: " + name + "\r\nHello " + name +"\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\nPlease enter your name: " + name + "\r\nHello " + name +"\r\n\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 1\r\nPlease enter your name: " + name + "\r\nHello " + name +"\r\n\r\nPress any key to exit... " }; m_ConsoleManager.OutputsUpdated += outputEntryNumber => { Assert.AreEqual( expectedOutput[outputEntryNumber - 1], m_ConsoleManager.ToString()); }; m_ProgramManager.Run(); } [TestCase("Ahmed")] [TestCase("")] [TestCase(" ")] public void RunWithInputAs2AndName(string name) { m_ConsoleManager.UserInputs.Enqueue("2"); m_ConsoleManager.UserInputs.Enqueue(name); m_ConsoleManager.UserInputs.Enqueue(new ConsoleKeyInfo()); var expectedOutput = new List<string> { "Welcome to my console app\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: ", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\nPlease enter your name: ", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\nPlease enter your name: " + name + "\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\nPlease enter your name: " + name + "\r\nGoodbye " + name + "\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\nPlease enter your name: " + name + "\r\nGoodbye " + name + "\r\n\r\n", "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: 2\r\nPlease enter your name: " + name + "\r\nGoodbye " + name + "\r\n\r\nPress any key to exit... " }; m_ConsoleManager.OutputsUpdated += outputEntryNumber => { Assert.AreEqual( expectedOutput[outputEntryNumber - 1], m_ConsoleManager.ToString()); }; m_ProgramManager.Run(); } [Test] public void RunShouldKeepTheMainMenuWhenInputIsNeither1Nor2() { m_ConsoleManager.UserInputs.Enqueue("any invalid input 1"); m_ConsoleManager.UserInputs.Enqueue("any invalid input 2"); m_ConsoleManager.UserInputs.Enqueue("Exit"); var expectedOutput = new List<string> { // initial menu "Welcome to my console app\r\n", // outputEntryNumber 1 "Welcome to my console app\r\n[1] Say Hello?\r\n", // outputEntryNumber 2 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n", // outputEntryNumber 3 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\n", // outputEntryNumber 4 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: ", // outputEntryNumber 5 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: any invalid input 1\r\n", // outputEntryNumber 6 // after first trial "", // outputEntryNumber 7 "Welcome to my console app\r\n", // outputEntryNumber 8 "Welcome to my console app\r\n[1] Say Hello?\r\n", // outputEntryNumber 9 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n", // outputEntryNumber 10 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\n", // outputEntryNumber 11 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: ", // outputEntryNumber 12 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: any invalid input 2\r\n", // outputEntryNumber 13 // after second trial "", // outputEntryNumber 14 "Welcome to my console app\r\n", // outputEntryNumber 15 "Welcome to my console app\r\n[1] Say Hello?\r\n", // outputEntryNumber 16 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n", // outputEntryNumber 17 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\n", // outputEntryNumber 18 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: ", // outputEntryNumber 19 "Welcome to my console app\r\n[1] Say Hello?\r\n[2] Say Goodbye?\r\n\r\nPlease enter a valid choice: Exit\r\n" // outputEntryNumber 20 }; m_ConsoleManager.OutputsUpdated += outputEntryNumber => { if (outputEntryNumber - 1 < expectedOutput.Count) { Assert.AreEqual( expectedOutput[outputEntryNumber - 1], m_ConsoleManager.ToString()); } }; m_ProgramManager.Run(); } } } 

अनस्प्लैश पर डेविड ग्रिफिथ्स द्वारा फोटो

आखिरकार

अब हम अपने कंसोल एप्लिकेशन को यूनिट परीक्षणों के साथ कवर करने में सक्षम हैं। हालाँकि, आप सोच सकते हैं कि यह हमारे यहाँ मौजूद एक साधारण अनुप्रयोग के लिए बहुत अधिक है। क्या यह अति नहीं है?


दरअसल, यह इस बात पर निर्भर करता है कि आप क्या कवर करना चाहते हैं। उदाहरण के लिए, हमारे सरल अनुप्रयोग में, मैंने यूआई पर प्रत्येक चरित्र को एक आवश्यकता के रूप में निपटाया जिसे इकाई परीक्षणों द्वारा कवर किया जाना चाहिए। इसलिए, यदि आप जाते हैं और मुख्य कार्यान्वयन पर एक चरित्र बदलते हैं, तो एक इकाई परीक्षण विफल हो जाएगा।


शायद आपके मामले में यह अलग होगा। हालाँकि, यह हमेशा अच्छा होगा यदि आप जानते हैं कि इसे सबसे छोटे पात्र तक कैसे करना है।


बस इतना ही, आशा है कि आपको यह लेख पढ़ने में उतना ही रोचक लगा होगा जितना मुझे इसे लिखने में लगा।


यहाँ भी प्रकाशित