paint-brush
Bao gồm đầy đủ ứng dụng bảng điều khiển .NET C# với các bài kiểm tra đơn vịtừ tác giả@ahmedtarekhasan
3,223 lượt đọc
3,223 lượt đọc

Bao gồm đầy đủ ứng dụng bảng điều khiển .NET C# với các bài kiểm tra đơn vị

từ tác giả Ahmed Tarek Hasan26m2023/01/06
Read on Terminal Reader

dài quá đọc không nổi

Một số đồng nghiệp phàn nàn rằng đôi khi họ không thể áp dụng TDD hoặc viết bài kiểm tra đơn vị cho một số mô-đun hoặc ứng dụng. Ứng dụng bảng điều khiển là một trong số đó. Làm cách nào tôi có thể kiểm tra ứng dụng Bảng điều khiển khi đầu vào được chuyển bằng các lần nhấn phím và đầu ra được hiển thị trên màn hình?!! Bạn không cần kiểm tra ứng dụng “Bảng điều khiển”, mà bạn muốn kiểm tra logic kinh doanh đằng sau ứng dụng đó.
featured image - Bao gồm đầy đủ ứng dụng bảng điều khiển .NET C# với các bài kiểm tra đơn vị
Ahmed Tarek Hasan HackerNoon profile picture

Phương pháp hay nhất để đạt được mức độ phù hợp 100% bằng cách sử dụng Phát triển theo hướng thử nghiệm (TDD), Tiêm phụ thuộc (DI), Đảo ngược kiểm soát (IoC) và Bộ chứa IoC.


Một số đồng nghiệp của tôi phàn nàn rằng đôi khi họ không thể áp dụng TDD hoặc viết bài kiểm tra đơn vị cho một số mô-đun hoặc ứng dụng, Ứng dụng bảng điều khiển là một trong số đó.


Làm cách nào tôi có thể kiểm tra ứng dụng Bảng điều khiển khi đầu vào được chuyển bằng tổ hợp phím và đầu ra được hiển thị trên màn hình?!!


Trên thực tế, điều này thỉnh thoảng xảy ra, bạn thấy mình đang cố gắng viết bài kiểm tra đơn vị cho thứ gì đó mà bạn dường như không có bất kỳ sự kiểm soát nào.


Ảnh của Sangga Rima Roman Selia trên Bapt

quan niệm sai lầm

Sự thật là, bạn vừa bỏ lỡ điểm. Bạn không cần kiểm tra ứng dụng “Bảng điều khiển”, bạn muốn kiểm tra logic nghiệp vụ đằng sau nó.


Khi bạn đang xây dựng ứng dụng Bảng điều khiển, bạn đang xây dựng ứng dụng cho ai đó sử dụng, anh ta mong muốn chuyển một số đầu vào và nhận được một số đầu ra tương ứng, và đó là điều bạn thực sự cần kiểm tra .


Bạn không muốn kiểm tra lớp tĩnh System.Console , đây là lớp dựng sẵn được bao gồm trong .NET framework và bạn phải tin tưởng Microsoft về điều này.


Bây giờ, bạn cần suy nghĩ về cách tách hai khu vực này thành các thành phần hoặc mô-đun riêng biệt để bạn có thể bắt đầu viết bài kiểm tra cho phần mình muốn mà không can thiệp vào phần còn lại, và đây là điều tôi sẽ giải thích cho bạn…


Ảnh của Mark Fletcher-Brown trên Unsplash

Ý tưởng

Đầu tiên, hãy nghĩ ra một ý tưởng ứng dụng Console đơn giản ngu ngốc và sử dụng nó làm ví dụ để áp dụng.


Đầu tiên, bạn có menu đơn giản này.


Hình ảnh của Ahmed Tarek


Khi bạn chọn tùy chọn 1 và nhập tên của bạn , bạn sẽ nhận được thông báo Hello như trong hình bên dưới. Nhấn enter sẽ đóng ứng dụng.


Hình ảnh của Ahmed Tarek


Khi bạn chọn tùy chọn 2 và nhập tên của bạn , bạn sẽ nhận được thông báo Goodbye như trong hình bên dưới. Nhấn enter sẽ đóng ứng dụng.


Hình ảnh của Ahmed Tarek


Quá đơn giản đúng không? Vâng tôi đồng ý với bạn. Tuy nhiên, giả sử rằng giao diện người dùng, chuỗi, ký tự và mọi thứ bạn nhìn thấy trên màn hình đều là một phần của yêu cầu.


Điều này có nghĩa là nếu bạn định viết các bài kiểm tra đơn vị, thì điều này cũng phải được đề cập theo cách mà một thay đổi nhỏ trên một ký tự trong mã sản xuất sẽ kích hoạt một bài kiểm tra đơn vị không thành công.


Ảnh của Brett Jordan trên Bapt

Kế hoạch

Đây là kế hoạch của chúng tôi:

  1. Xây dựng ứng dụng Console theo cách xấu truyền thống.
  2. Xem liệu chúng ta có thể viết các bài kiểm tra đơn vị tự động hay không.
  3. Triển khai lại ứng dụng Console một cách tốt.
  4. Viết một số bài kiểm tra đơn vị.

Ảnh của Mehdi trên Bapt

con đường xấu

Đơn giản, làm mọi thứ ở một nơi.


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


Những gì chúng ta có thể nhận thấy ở đây:

  1. Mọi thứ đều ở một nơi.
  2. Chúng tôi đang trực tiếp sử dụng lớp System.Console tĩnh.
  3. Chúng tôi không thể kiểm tra logic nghiệp vụ mà không va vào System.Console .

Ảnh của Brett Jordan trên Bapt

Cố gắng viết bài kiểm tra đơn vị

Có thật không? bạn có thực sự mong đợi có thể viết một bài kiểm tra đơn vị cho mã đó không?

Dưới đây là những thách thức:

  1. Tùy thuộc vào các lớp tĩnh như System.Console .
  2. Không thể xác định và cô lập các phụ thuộc.
  3. Không thể thay thế các phần phụ thuộc bằng Mocks hoặc Stub.

Nếu bạn có thể làm điều gì đó về nó, bạn là một anh hùng… tin tôi đi.


Ảnh của Volkan Olmez trên Bapt

con đường tốt

Bây giờ, hãy chia giải pháp của chúng ta thành các mô-đun nhỏ hơn.


Trình quản lý bảng điều khiển

Đây là mô-đun chịu trách nhiệm cung cấp chức năng chúng tôi cần từ Bảng điều khiển… bất kỳ bảng điều khiển nào.


Mô-đun này sẽ bao gồm hai phần:

  1. trừu tượng.
  2. Triển khai.


Vì vậy, chúng tôi sẽ có những điều sau đây:

  1. IConsoleManager : Đây là giao diện xác định những gì chúng tôi đang mong đợi từ bất kỳ Trình quản lý bảng điều khiển nào.
  2. ConsoleManagerBase : Đây là lớp trừu tượng triển khai IConsoleManager và cung cấp bất kỳ triển khai chung nào giữa tất cả Trình quản lý bảng điều khiển.
  3. ConsoleManager : Đây là cài đặt Trình quản lý bảng điều khiển mặc định bao bọc System.Console và thực sự được sử dụng trong thời gian chạy.


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


Những gì chúng ta có thể nhận thấy ở đây:

  1. Bây giờ chúng ta có IConsoleManager .
  2. Chúng ta có thể sử dụng Mocks and Stub để thay thế IConsoleManager trong khi viết bài kiểm tra đơn vị.
  3. Đối với lớp cơ sở chung ConsoleManagerBase chúng tôi không cung cấp bất kỳ triển khai chung nào cho trẻ em sử dụng.
  4. Tôi biết đây không phải là điều tốt nhất để làm, tuy nhiên, tôi đang làm điều đó ở đây chỉ để nhắc bạn rằng tùy chọn này luôn sẵn có và bạn có thể sử dụng nó bất cứ khi nào cần.

Quản lý chương trình

Đây là mô-đun chịu trách nhiệm cung cấp chức năng ứng dụng chính.


Mô-đun này sẽ bao gồm hai phần:

  1. trừu tượng.
  2. Triển khai.


Vì vậy, chúng tôi sẽ có những điều sau đây:

  1. IProgramManager : Đây là giao diện xác định những gì chúng tôi đang mong đợi từ bất kỳ Trình quản lý chương trình nào.
  2. ProgramManagerBase : Đây là lớp trừu tượng triển khai IProgramManager và cung cấp bất kỳ triển khai chung nào giữa tất cả các Trình quản lý chương trình.
  3. ProgramManager quản lý chương trình : Đây là triển khai Trình quản lý chương trình mặc định được sử dụng thực sự trong thời gian chạy. Nó cũng phụ thuộc vào 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"); } } }


Những gì chúng ta có thể nhận thấy ở đây:

  1. Bây giờ chúng ta đã xác định rõ sự phụ thuộc của Trình quản lý chương ProgramManager vào IConsoleManager .
  2. Chúng tôi có IProgramManager và chúng tôi có thể sử dụng giả và sơ khai để thay thế IProgramManager trong khi viết bài kiểm tra đơn vị.
  3. Đối với lớp cơ sở chung ProgramManagerBase , chúng tôi không cung cấp bất kỳ triển khai chung nào cho trẻ em sử dụng.
  4. Tôi biết đây không phải là điều tốt nhất để làm, tuy nhiên, tôi đang làm điều đó ở đây chỉ để nhắc bạn rằng tùy chọn này luôn sẵn có và bạn có thể sử dụng nó bất cứ khi nào cần.


Lớp ProgramManager có thể được chia thành các phần nhỏ hơn. Điều đó sẽ giúp việc theo dõi và kiểm tra đơn vị trở nên dễ dàng hơn. Tuy nhiên, đây là điều tôi để lại cho bạn làm.


Ứng dụng giao diện điều khiển

Đây là ứng dụng chính.


Ở đây chúng ta sẽ sử dụng Ninject làm vùng chứa IoC của chúng tôi. Nó rất đơn giản để sử dụng và bạn luôn có thể kiểm tra tài liệu trực tuyến của họ.


Trong dự án Ứng dụng bảng điều khiển chính, chúng tôi sẽ tạo tệp NinjectDependencyResolver.cs . Tập tin này sẽ như sau.


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


Những gì chúng ta có thể nhận thấy ở đây:

  1. Lớp NinjectDependencyResolver đang kế thừa NinjectModule .
  2. Chúng tôi đang ghi đè phương thức void Load() nơi chúng tôi đang đặt các ràng buộc của mình như mong đợi.


Bây giờ, trên 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(); } } }


Những gì chúng ta có thể nhận thấy ở đây:

  1. Chúng tôi phụ thuộc vào IProgramManager .
  2. Chúng tôi đã tạo bộ chứa IoC thông qua var kernel = new StandardKernel(); .
  3. Sau đó, chúng tôi đã tải các phụ thuộc vào bộ chứa IoC thông qua kernel.Load(Assembly.GetExecutingAssembly()); . Điều này hướng dẫn Ninject lấy các liên kết của nó từ tất cả các lớp kế thừa NinjectModule bên trong hợp ngữ/dự án hiện tại.
  4. Điều này có nghĩa là các liên kết sẽ đến từ lớp NinjectDependencyResolver của chúng ta vì nó đang kế thừa NinjectModule và nằm bên trong hội đồng/dự án hiện tại.
  5. Để lấy một phiên bản của IProgramManager chúng tôi đang sử dụng bộ chứa IoC như sau kernel.Get<IProgramManager>(); .


Bây giờ, hãy xem liệu thiết kế và công việc chúng tôi đã thực hiện cho đến thời điểm này có khắc phục được sự cố của chúng tôi hay không.


Ảnh của Markus Winkler trên Bapt

Khoảnh khắc của sự thật

Vì vậy, câu hỏi bây giờ là, chúng ta có thể bao quát Ứng dụng Bảng điều khiển của mình bằng các bài kiểm tra đơn vị không? Để trả lời câu hỏi này, chúng ta hãy thử viết một số bài kiểm tra đơn vị…


Sơ khai hoặc Mocks

Nếu bạn có một số kinh nghiệm với thử nghiệm đơn vị, bạn nên biết rằng chúng tôi có Stub và Mocks được sử dụng để thay thế các phần phụ thuộc của chúng tôi.


Để giải trí, tôi sẽ sử dụng sơ khai cho ví dụ của chúng ta ở đây.


Vì vậy, tôi sẽ định nghĩa ConsoleManagerStub là sơ khai cho IConsoleManager như sau:


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


Và cuối cùng, các bài kiểm tra đơn vị sẽ như sau:


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

Ảnh của david Griffiths trên Unsplash

Cuối cùng

Giờ đây, chúng tôi đã có thể bao quát Ứng dụng Bảng điều khiển của mình bằng các bài kiểm tra đơn vị. Tuy nhiên, bạn có thể nghĩ rằng điều này là quá nhiều đối với một ứng dụng đơn giản như ứng dụng chúng tôi có ở đây. Đây không phải là quá mức cần thiết?


Trên thực tế, nó phụ thuộc vào những gì bạn muốn trang trải. Ví dụ: trong ứng dụng đơn giản của chúng tôi, tôi đã xử lý mọi ký tự trên giao diện người dùng như một yêu cầu phải được bao phủ bởi các bài kiểm tra đơn vị. Vì vậy, nếu bạn thay đổi một ký tự trong quá trình triển khai chính, thì một bài kiểm tra đơn vị sẽ thất bại.


Có lẽ trong trường hợp của bạn, nó sẽ khác. Tuy nhiên, sẽ luôn tốt nếu bạn biết cách thực hiện ngay cả với ký tự nhỏ nhất.


Vậy đó, hy vọng bạn thấy thú vị khi đọc bài viết này như tôi thấy khi viết nó.


Cũng được xuất bản ở đây