paint-brush
নির্মাতার সাথে পরিচয় করিয়ে দেওয়া হচ্ছে: টেস্ট-ড্রিভেন ডেভেলপমেন্টে আপনার বন্ধু (TDD)দ্বারা@easytdd
481 পড়া
481 পড়া

নির্মাতার সাথে পরিচয় করিয়ে দেওয়া হচ্ছে: টেস্ট-ড্রিভেন ডেভেলপমেন্টে আপনার বন্ধু (TDD)

দ্বারা Kazys Račkauskas21m2024/08/23
Read on Terminal Reader

অতিদীর্ঘ; পড়তে

বিল্ডার: টেস্ট-ড্রাইভেন ডেভেলপমেন্টে আপনার বন্ধু (TDD) বিল্ডার ডেভেলপারদের একটি সাবলীল ইন্টারফেস ব্যবহার করে ধাপে ধাপে টেস্ট ডেটা অবজেক্ট তৈরি করতে দেয় যা পঠনযোগ্যতা বাড়ায় এবং শব্দচয়ন কমায়। বিল্ডার ক্লাস হল একটি চমৎকার জায়গা যা সব সাধারণ এবং প্রান্তের কেস অবজেক্টকে সংজ্ঞায়িত এবং সংগ্রহ করার জন্য। অনেক ক্ষেত্রে, বৈশিষ্ট্যের শুধুমাত্র একটি অংশ নির্দিষ্ট পরীক্ষার জন্য প্রাসঙ্গিক।
featured image - নির্মাতার সাথে পরিচয় করিয়ে দেওয়া হচ্ছে: টেস্ট-ড্রিভেন ডেভেলপমেন্টে আপনার বন্ধু (TDD)
Kazys Račkauskas HackerNoon profile picture

বিল্ডার প্যাটার্ন

আজ, আমি পরীক্ষা-চালিত উন্নয়নে নির্মাতা প্যাটার্ন সম্পর্কে কথা বলব। আপনি যদি ইতিমধ্যে পরীক্ষা নিয়ে কাজ করছেন, আপনি সম্ভবত লক্ষ্য করেছেন যে সমস্ত ইনপুট ডেটা তৈরি করা কতটা সময়সাপেক্ষ হতে পারে। প্রায়শই, ডেটার একই সেট, বা সামান্য পার্থক্য সহ ডেটা, একটি সিস্টেমের পরীক্ষা স্যুটে অনেক পরীক্ষায় ব্যবহৃত হয়। বিল্ডার এখানে সাহায্য করে। এটি দুটি উদ্দেশ্য পরিবেশন করে:


  • নির্মাতা ডেভেলপারদের একটি সাবলীল ইন্টারফেস ব্যবহার করে ধাপে ধাপে টেস্ট ডেটা অবজেক্ট তৈরি করতে দেয় যা পঠনযোগ্যতা বাড়ায় এবং শব্দচয়ন কমায়।


  • বিল্ডার ক্লাস হল সব সাধারণ এবং প্রান্ত-কেস বস্তু সংজ্ঞায়িত এবং সংগ্রহ করার জন্য একটি চমৎকার জায়গা। উদাহরণস্বরূপ, একজন যাত্রীর জন্য, এটি একজন পুরুষ, মহিলা, ছেলে, মেয়ে, শিশু, ইত্যাদি হতে পারে৷ একটি ভ্রমণপথের জন্য, এটি একমুখী, রাউন্ড ট্রিপ, প্রত্যক্ষ, পরোক্ষ ইত্যাদি হতে পারে৷


একটি উদাহরণের জন্য আমি Invoice ক্লাস নেব, একটি খুব সরলীকৃত সংস্করণ এরকম কিছু হতে পারে:

 public class Invoice { public Invoice( string invoiceNo, string customer, string countryCode, DateTime invoiceDate, IReadOnlyList<InvoiceLine> lines) { InvoiceNo = invoiceNo; InvoiceDate = invoiceDate; Customer = customer; CountryCode = countryCode; Lines = lines; } public string InvoiceNo { get; } public string Customer { get; } public string CountryCode { get; } public DateTime InvoiceDate { get; } public decimal TotalAmount => Lines.Sum(x => x.TotalPrice); public IReadOnlyList<InvoiceLine> Lines { get; } } public class InvoiceLine { public InvoiceLine( string itemCode, decimal unitCount, decimal unitPrice, decimal vat) { ItemCode = itemCode; UnitCount = unitCount; UnitPrice = unitPrice; Vat= vat; } public string ItemCode { get; } public decimal UnitCount { get; } public decimal UnitPrice { get; } public decimal Vat { get; } public decimal TotalPrice => UnitCount * UnitPrice * (1 + Vat / 100); }

একটি Invoice অবজেক্ট তৈরি করতে, আমাকে Invoice এবং InvoiceLine কনস্ট্রাক্টরদের অনেকগুলি মান প্রদান করতে হবে। অনেক ক্ষেত্রে, বৈশিষ্ট্যের শুধুমাত্র একটি অংশ নির্দিষ্ট পরীক্ষার জন্য প্রাসঙ্গিক। এখানে, নির্মাতারা সাহায্য করতে আসে।


InvoiceLine নির্মাতা এইরকম দেখতে পারেন:

 public partial class InvoiceLineBuilder { private string _itemCode; private decimal _unitCount; private decimal _unitPrice; private decimal _vat; public static implicit operator InvoiceLine(InvoiceLineBuilder builder) => builder.Build(); public static InvoiceLineBuilder Default() { return new InvoiceLineBuilder( "001", 1, 100, 21 ); } public InvoiceLineBuilder( string itemCode, decimal unitCount, decimal unitPrice, decimal vat) { _itemCode = itemCode; _unitCount = unitCount; _unitPrice = unitPrice; _vat = vat; } public InvoiceLine Build() { return new InvoiceLine( _itemCode, _unitCount, _unitPrice, _vat ); } public InvoiceLineBuilder WithItemCode(string value) { _itemCode = value; return this; } public InvoiceLineBuilder WithUnitCount(decimal value) { _unitCount = value; return this; } public InvoiceLineBuilder WithUnitPrice(decimal value) { _unitPrice = value; return this; } public InvoiceLineBuilder WithVat(decimal vat) { _vat = value; return this; } }


Invoice জন্য নির্মাতা এইরকম কিছু দেখতে পারে:

 public partial class InvoiceBuilder { private string _invoiceNo; private string _customer; private string _countryCode; private DateTime _invoiceDate; private IReadOnlyList<InvoiceLine> _lines; public static implicit operator Invoice(InvoiceBuilder builder) => builder.Build(); public static InvoiceBuilder Default() { return new InvoiceBuilder( "S001", "AB VeryImportantCustomer", "SV", DateTime.Parse("2024-01-01"), new [] { InvoiceLineBuilder .Default() .Build() } ); } public InvoiceBuilder( string invoiceNo, string customer, string countryCode, DateTime invoiceDate, IReadOnlyList<InvoiceLine> lines) { _invoiceNo = invoiceNo; _customer = customer; _countryCode = countryCode; _invoiceDate = invoiceDate; _lines = lines; } public Invoice Build() { return new Invoice( _invoiceNo, _invoiceDate, _lines ); } public InvoiceBuilder WithInvoiceNo(string value) { _invoiceNo = value; return this; } public InvoiceBuilder WithCustomer(string value) { _customer = value; return this; } public InvoiceBuilder WithCountryCode(string value) { _countryCode = value; return this; } public InvoiceBuilder WithInvoiceDate(DateTime value) { _invoiceDate = value; return this; } public InvoiceBuilder WithLines(IReadOnlyList<InvoiceLine> value) { _lines = value; return this; } public InvoiceBuilder WithLines(params InvoiceLine[] value) { _lines = value; return this; } }


যদি একটি পরীক্ষায় শুধুমাত্র তার মোট মূল্য সম্পত্তির জন্য একটি Invoice বস্তুর প্রয়োজন হয়, তাহলে Invoice এভাবে তৈরি করা যেতে পারে:

 var invoice = InvoiceBuilder .Default() .WithLines( InvoiceLineBuilder .Default .WithUnitPrice(158) );


যেহেতু ইনভয়েস লাইনের যোগফল দ্বারা মোট মূল্য গণনা করা হয় এবং ইনভয়েস লাইনের জন্য ডিফল্ট ইউনিট গণনা 1 হয়, তাহলে ইনভয়েস লাইনের জন্য ইউনিট মূল্য সেট করা যথেষ্ট। একাধিক পরীক্ষায় অনুরূপ কার্যকারিতা প্রয়োজন হলে, আমরা আরও যেতে পারি এবং InvoiceBuilder নিম্নলিখিত পদ্ধতিটি যুক্ত করতে পারি:

 public static InvoiceBuilder DefaultWithTotalPrice(decimal totalPrice) { return new InvoiceBuilder( "S001", DateTime.Parse("2023-01-01"), new[] { InvoiceLineBuilder .Default() .WithUnitPrice(totalPrice) .Build() } ); }

পূর্বনির্ধারিত সেটআপের সংগ্রহ

উপরে উল্লিখিত হিসাবে, বিল্ডার ক্লাস ক্লাসের জন্য সমস্ত সাধারণ এবং প্রান্ত কেস সংগ্রহ করার জন্য একটি দুর্দান্ত জায়গা। এখানে, আমি সেই সম্ভাব্য ক্ষেত্রে কয়েকটি প্রদান করব:


  • নিয়মিত ভ্যাট থাকা আইটেম সহ একটি চালান
  • ভ্যাট কমানো আইটেম সহ একটি চালান
  • মিশ্র ভ্যাটযুক্ত আইটেম সহ একটি চালান
  • একটি EU দেশের একটি চালান
  • একটি NA দেশের একটি চালান৷
  • চীনের একটি চালান


আমার দৃষ্টিকোণ থেকে, আমাদের সিস্টেম পরিচালনা করে এমন বিভিন্ন ক্ষেত্রে জ্ঞান সংগ্রহ করার জন্য এটি একটি দুর্দান্ত জায়গা। এটি নতুন বিকাশকারীদের জন্য একটি দরকারী জ্ঞান বেস হিসাবে কাজ করে যাতে সিস্টেমটি পরিচালনা করতে হবে তা বোঝার জন্য। যদি আমি একটি ক্ষেত্রে নতুন, আমি এমনকি সম্ভাব্য প্রান্ত কেস মনে নাও হতে পারে. উপরে উল্লিখিত কিছু ক্ষেত্রে থেকে এখানে একটি কোড উদাহরণ রয়েছে:

 public static InvoiceBuilder ForEUCountry() { return Default() .WithCountryCode("SV"); } public static InvoiceBuilder ForUSA() { return Default() .WithCountryCode("USA"); } public static InvoiceBuilder ForChina() { return Default() .WithCountryCode("CN"); } public InvoiceBuilder WithRegularVat() { return this .WithLines( InvoiceLineBuilder .Default .WithItemCode("S001") .WithVat(21), InvoiceLineBuilder .Default .WithItemCode("S002") .WithVat(21) ); } public InvoiceBuilder WithReducedVat() { return this .WithLines( InvoiceLineBuilder .Default .WithItemCode("S001") .WithVat(9), InvoiceLineBuilder .Default .WithItemCode("S002") .WithVat(9) ); } public InvoiceBuilder WithMixedVat() { return this .WithLines( InvoiceLineBuilder .Default .WithItemCode("S001") .WithVat(21), InvoiceLineBuilder .Default .WithItemCode("S002") .WithVat(9) ); }

এখন আমরা উপরের একটি মিশ্রণ তৈরি করতে পারি। উদাহরণ স্বরূপ, যদি কোনো পরীক্ষার ক্ষেত্রে কোনো ইউরোপীয় ইউনিয়নের গ্রাহকের জন্য একটি চালানের প্রয়োজন হয় যার ইনভয়েস লাইনে ভ্যাট মিশ্রিত থাকে, আমি নিম্নলিখিতগুলি করতে পারি:

 [Test] public void SomeTest() { //arrange var invoice = InvoiceBuilder .ForEU() .WithMixedVat(); //act ... //assert ... }

এটি কেবল একটি সাধারণ উদাহরণ, তবে আমি আশা করি আপনি ধারণাটি বুঝতে পেরেছেন।


যখন আমাদের কাছে একটি বড়, জটিল বস্তু থাকে তখন একজন নির্মাতা দরকারী, কিন্তু শুধুমাত্র কয়েকটি ক্ষেত্র পরীক্ষার জন্য প্রাসঙ্গিক।


আরেকটি দরকারী ক্ষেত্রে যখন আমি নির্দিষ্ট মানগুলির উপর ভিত্তি করে একাধিক পরিস্থিতিতে পরীক্ষা করতে চাই। একটি ছাড়া সমস্ত বৈশিষ্ট্য একই থাকে, এবং আমি শুধুমাত্র একটি পরিবর্তন করি। এটি পার্থক্যটিকে হাইলাইট করা সহজ করে তোলে, যার কারণে পরিষেবা বা বস্তু ভিন্নভাবে আচরণ করে।

বিল্ডার ক্লাস তৈরি করার উপায়

আপনার নিজের হাতে কোড

প্রথমত, আপনি নিজেরাই একটি বিল্ডার ক্লাস তৈরি করতে পারেন। এর জন্য সময় বা অর্থের কোনো প্রাথমিক বিনিয়োগের প্রয়োজন হয় না এবং আপনি কীভাবে এটি তৈরি করেন তাতে আপনার অনেক স্বাধীনতা রয়েছে। অনুলিপি করা, আটকানো এবং প্রতিস্থাপন করা কার্যকর হতে পারে, তবে এটি এখনও বেশ কিছুটা সময় নেয়, বিশেষ করে বড় ক্লাসের জন্য।

আপনার নিজের কোড জেনারেটর তৈরি করুন

যখন আমি কোড জেনারেশন দিয়ে শুরু করি, তখন আমি এটির জন্য একটি একক পরীক্ষা সেট আপ করে শুরু করি। এই পরীক্ষা আসলে কিছুই পরীক্ষা করেনি; এটি কেবল একটি প্রকার গ্রহণ করেছে, প্রতিফলন ব্যবহার করে সমস্ত বৈশিষ্ট্য পুনরুদ্ধার করেছে, একটি হার্ডকোডেড টেমপ্লেট থেকে একটি বিল্ডার ক্লাস তৈরি করেছে এবং এটি পরীক্ষা রানার আউটপুট উইন্ডোতে লিখেছে। আমাকে যা করতে হয়েছিল তা হল একটি ক্লাস ফাইল তৈরি করা এবং পরীক্ষার রানার আউটপুট উইন্ডো থেকে সামগ্রীটি কপি/পেস্ট করা।

বিল্ডার জেনারেটর

বিল্ডারজেনারেটর সম্পর্কে সমস্ত এখানে পাওয়া যাবে। এটি .NET ইনক্রিমেন্টাল সোর্স জেনারেটর ব্যাখ্যা করে। এর মানে লক্ষ্য শ্রেণী পরিবর্তন হলে বিল্ডার কোড লাইভ পুনরায় জেনারেট করা হয়। সুতরাং, উপরের পদ্ধতির তুলনায় কোন ঝামেলা বা ম্যানুয়াল কাজ নেই। শুধু একটি বিল্ডার ক্লাস তৈরি করুন, টার্গেট ক্লাস টাইপের সাথে BuilderFor অ্যাট্রিবিউট যোগ করুন এবং সমস্ত With মেথড স্বয়ংক্রিয়ভাবে তৈরি হয় এবং ব্যবহারের জন্য প্রস্তুত।

 [BuilderFor(typeof(InvoiceLine))] public partial class InvoiceLineBuilder { public static InvoiceLineBuilder Default() { return new InvoiceLineBuilder() .WithItemCode("S001") .WithUnitCount(1); } }

আমি এটির সাথে খুব বেশি কাজ করিনি, তবে লেখার সময় এটি 82.7K ডাউনলোড সহ একটি বিস্তৃত ব্যবহারকারী বেস রয়েছে বলে মনে হচ্ছে। আমি কয়েকটি সমস্যা লক্ষ্য করেছি যা আমাকে অন্য বিকল্পগুলি বেছে নিতে বাধ্য করেছে:


  • বিল্ডার শ্রেণী লক্ষ্য শ্রেণীর চেয়ে ভিন্ন প্রকল্পে থাকলে সমাধানটি তৈরি করতে ব্যর্থ হয়। এটি অন্য প্রকল্পে হতে পারে, কিন্তু নামস্থান অবশ্যই একই থাকতে হবে। অন্যথায়, আপনি নিম্নলিখিত ত্রুটিগুলি দেখতে পাবেন::

  • এটি কনস্ট্রাক্টর প্যারামিটার সমর্থন করে না এবং যদি টার্গেট ক্লাসে প্যারামিটারবিহীন কনস্ট্রাক্টর না থাকে তবে ত্রুটির সাথে ব্যর্থ হয়।:

আমাদের অন্যান্য বিকল্প কি আছে অন্বেষণ করা যাক.

জাল জেনারেটর

লেখার সময় এটি 82.2M এরও বেশি মোট ডাউনলোড (এবং বর্তমান সংস্করণের জন্য 186.1K) সহ একটি খুব জনপ্রিয় লাইব্রেরি। লাইব্রেরির লেখক বলেছেন, এটি একটি জাল ডেটা জেনারেটর যা পূর্বনির্ধারিত নিয়মের উপর ভিত্তি করে অসংখ্য বস্তু তৈরি করতে সক্ষম। টিডিডিতে নির্মাতার প্যাটার্নটি ঠিক কী তা নয়, তবে এটি মানিয়ে নেওয়া যেতে পারে।


Bogus.Faker ব্যবহার করার বিভিন্ন উপায় আছে, কিন্তু আমি এখানে কীভাবে বিল্ডার প্যাটার্নটি নকল করতে হয় তার উপর ফোকাস করব।


একটি বস্তু তৈরি করার সবচেয়ে সহজ উপায় হল Bogus.Faker হল:

 [Test] public void BogusTest() { var faker = new Faker<InvoiceLine2>(); var invoiceLine = faker.Generate(); Assert.IsNotNull(invoiceLine); }


এটি ডিফল্ট মান সহ InvoiceLine2 এর একটি উদাহরণ তৈরি করে, যার অর্থ নাল এবং শূন্য। কিছু মান সেট করতে, আমি নিম্নলিখিত সেটআপ ব্যবহার করব:

 [Test] public void BogusTest() { var faker = new Faker<InvoiceLine2>() .RuleFor(x => x.ItemCode, f => f.Random.AlphaNumeric(5)) .RuleFor(x => x.UnitPrice, f => f.Random.Decimal(10, 1000)) .RuleFor(x => x.UnitCount, f => f.Random.Number(1, 5)) .RuleFor(x => x.Vat, f => f.PickRandom(21, 9, 0)); var invoiceLine = faker.Generate(); Assert.IsNotNull(invoiceLine); ToJson(invoiceLine); }


উপরের কোডটি এলোমেলো মান সহ একটি চালান লাইন অবজেক্ট তৈরি করে। একটি উদাহরণ এই মত দেখতে পারে:

 { "ItemCode": "gwg7y", "UnitCount": 3.0, "UnitPrice": 597.035612417891230, "Vat": 0.0, "TotalPrice": 1791.106837253673690 }


এটি দরকারী, কিন্তু প্রতিটি পরীক্ষার নিজস্ব সেটআপ প্রয়োজন। পরিবর্তে, আমরা একটি বিল্ডার ক্লাস তৈরি করতে পারি:

 public class InvoiceLineBuilder: Faker<InvoiceLine2> { public static InvoiceLineBuilder Default() { var faker = new InvoiceLineBuilder(); faker .RuleFor(x => x.ItemCode, f => f.Random.AlphaNumeric(5)) .RuleFor(x => x.UnitPrice, f => f.Random.Decimal(10, 1000)) .RuleFor(x => x.UnitCount, f => f.Random.Number(1, 5)) .RuleFor(x => x.Vat, f => f.PickRandom(21, 9, 0)); return faker; } }


ব্যবহার এই মত কিছু দেখতে হবে:

 [Test] public void BogusTest() { var faker = TestDoubles.Bogus.InvoiceLineBuilder .Default() .RuleFor(x => x.ItemCode, f => "S001") .RuleFor(x => x.UnitPrice, f => 100); var invoiceLine = faker.Generate(); Assert.IsNotNull(invoiceLine); ToJson(invoiceLine); }


এবং আউটপুট:

 { "ItemCode": "S001", "UnitCount": 2.0, "UnitPrice": 100.0, "Vat": 9.0, "TotalPrice": 218.00 }

আমার দৃষ্টিকোণ থেকে, এটি নিয়মিত বিল্ডার প্যাটার্নের চেয়ে একটু বেশি শব্দযুক্ত। উপরন্তু, আমি র্যান্ডম মান ব্যবহার করার একটি অনুরাগী নই. এটি একটি বড় সমস্যা নয়, কিন্তু সমস্যা দেখা দেয় যখন একটি শ্রেণির বৈশিষ্ট্যগুলি একটি কনস্ট্রাক্টর ব্যবহার করে আরম্ভ করা হয় এবং এতে সেটার থাকে না। তারপর এটি একটি নির্মাতা হিসাবে কাজ করে না, এবং প্রতিটি সেটআপ স্ট্যাটিক হয়ে যায়।

 var faker = new InvoiceLineBuilder(); faker .CustomInstantiator(f => new InvoiceLine( f.Random.AlphaNumeric(5), f.Random.Decimal(10, 1000), f.Random.Number(1, 5), f.PickRandom(21, 9, 0) ) );

এন বিল্ডার

এটিও একটি খুব জনপ্রিয় লাইব্রেরি যেখানে মোট 13.2 মিলিয়ন ডাউনলোড (এবং বর্তমান সংস্করণের জন্য 7.2 মিলিয়ন)। যদিও এটি সম্প্রতি সক্রিয়ভাবে বিকশিত হয়নি, শেষ সংস্করণটি 2019 সালে প্রকাশিত হয়েছিল৷ মূলত, এটি Bogus.Faker-এর মতোই৷ এমনকি একটি নির্দিষ্ট IpropertyNamer প্রয়োগ করে এলোমেলো মান প্রদানের জন্য বোগাস পুনরায় ব্যবহার করা সম্ভব হওয়া উচিত।


আসুন কোন বৈশিষ্ট্য সেট না করে এটি ব্যবহার করার চেষ্টা করুন:

 [Test] public void NBuilderTest() { var invoiceLine = Builder<InvoiceLine2> .CreateNew() .Build(); Assert.IsNotNull(invoiceLine); ToJson(invoiceLine); }


এটি নিম্নলিখিত আউটপুট উত্পাদন করে::

 { "ItemCode": "ItemCode1", "UnitCount": 1.0, "UnitPrice": 1.0, "Vat": 1.0, "TotalPrice": 1.01 }


এই পোস্টের উদ্দেশ্য হল কিভাবে একটি পুনঃব্যবহারযোগ্য বিল্ডার ক্লাস তৈরি করা যায় তা দেখানো। চলুন শুরু করা যাক:

 public class InvoiceLineBuilder { public static ISingleObjectBuilder<InvoiceLine2> Default() { return Builder<InvoiceLine2> .CreateNew() .With(x => x.ItemCode, "S001") .With(x => x.UnitCount, 1) .With(x => x.UnitPrice, 100) .With(x => x.Vat, 21); } }


এবং এখানে ব্যবহার:

 [Test] public void NBuilderTest() { var invoiceLine = TestDoubles.NBuilder.InvoiceLineBuilder .Default() .With(x => x.ItemCode, "S002") .With(x => x.Vat, 9) .Build(); Assert.IsNotNull(invoiceLine); ToJson(invoiceLine); }


এবং আউটপুট:

 { "ItemCode": "S002", "UnitCount": 1.0, "UnitPrice": 100.0, "Vat": 9.0, "TotalPrice": 109.00 }


Bogus.Faker-এর মতো, আপনি মানগুলিকে ওভাররাইড করতে পারবেন না যদি একটি শ্রেণী সম্পত্তি একটি কনস্ট্রাক্টর ব্যবহার করে সেট করা হয় এবং সেটার না থাকে । আপনি যদি এই জাতীয় সম্পত্তির জন্য উইথ পদ্ধতি ব্যবহার করার চেষ্টা করেন তবে এটি নিম্নলিখিত ব্যতিক্রম সহ ব্যর্থ হবে:

 System.ArgumentException : Property set method not found.

EasyTdd.Generators.Builder

EasyTdd.Generators.Builder হল একটি Nuget প্যাকেজ এবং EasyTdd - ভিজ্যুয়াল স্টুডিও এক্সটেনশনের সাথে মিলিতভাবে কাজ করে। এই প্যাকেজটি EasyTdd এক্সটেনশন দ্বারা ব্যবহৃত টেমপ্লেটগুলি থেকে নির্মাতা তৈরি করতে একটি .NET ক্রমবর্ধমান উত্স জেনারেটর ব্যবহার করে। বিল্ডার জেনারেটর প্রপার্টি সেটার, কনস্ট্রাক্টর প্যারামিটার এবং উভয়ের সমন্বয় পরিচালনা করে। এটি জেনেরিক পরামিতি সমর্থন করে।


এটি একটি নির্মাতা তৈরি করার জন্য আমার পছন্দের উপায়। অন্যান্য বিকল্পগুলির তুলনায় এখানে সুবিধাগুলি রয়েছে:

  • বিল্ডার শ্রেণীটি শুধুমাত্র কয়েকটি ক্লিকের মাধ্যমে তৈরি হয়।


  • বিল্ডার ক্লাস জেনারেশনের জন্য একটি ইনক্রিমেন্টাল সোর্স জেনারেটর ব্যবহার করা হয়। এর ফলে সোর্স ক্লাসের প্রতিটি পরিবর্তনে বিল্ডার ক্লাস স্বয়ংক্রিয় আপডেট হয়।


  • টেমপ্লেটিং সমর্থন. আপনি সহজেই আমার প্রয়োজনে টেমপ্লেট মানিয়ে নিতে পারেন.


  • উভয় কন্সট্রাকটর প্যারামিটার, সেটারের বৈশিষ্ট্য বা উভয়ের মিশ্রণ ব্যবহার করে শুরু করা যেতে পারে এমন ক্লাসগুলির জন্য বিরামবিহীন সমর্থন।


  • জেনেরিক ক্লাস সমর্থন।


যখন ভিজ্যুয়াল স্টুডিওতে EasyTdd ইনস্টল করা হয়, তখন টার্গেট ক্লাসে দ্রুত অ্যাকশন মেনু খুলুন এবং "বৃদ্ধিশীল বিল্ডার তৈরি করুন" নির্বাচন করুন:

এই ক্রিয়াটি BuilderFor অ্যাট্রিবিউট সেট সহ একটি আংশিক বিল্ডার ক্লাস তৈরি করে:

 [EasyTdd.Generators.BuilderFor(typeof(InvoiceLine))] public partial class InvoiceLineBuilder { public static InvoiceLineBuilder Default() { return new InvoiceLineBuilder( () => default, // Set default itemCode value () => default, // Set default unitCount value () => default, // Set default unitPrice value () => default // Set default vat value ); } }

বিল্ডার কোড নিজেই ব্যাকগ্রাউন্ডে তৈরি হয় এবং এই আংশিক ক্লাসটি সাধারণ/এজ কেস সেটআপের জন্য তৈরি। default পরিবর্তে ডিফল্ট মান সেট করতে দ্বিধা বোধ করুন।


এটি সেট আপ এবং এটি কীভাবে কাজ করে সে সম্পর্কে আরও এখানে পাওয়া যাবে।


ভাল অংশ হল যে যদি আমার এলোমেলো মানগুলির প্রয়োজন হয়, আমি এখানে বোগাস ব্যবহার করতে পারি:

 public static InvoiceLineBuilder Random() { var f = new Faker(); return new InvoiceLineBuilder( () => f.Random.AlphaNumeric(5), () => f.Random.Decimal(10, 1000), () => f.Random.Number(1, 5), () => f.PickRandom(21, 9, 0) ); }


ব্যবহার:

 [Test] public void EasyTddBuilder() { var invoiceLine = TestDoubles.Builders.InvoiceLineBuilder .Random() .WithUnitPrice(100) .WithUnitCount(1) .Build(); Assert.IsNotNull(invoiceLine); ToJson(invoiceLine); }


এবং আউটপুট:

 { "ItemCode": "ana0i", "UnitCount": 1.0, "UnitPrice": 100.0, "Vat": 9.0, "TotalPrice": 109.00 }

বিশুদ্ধ EasyTdd

EasyTdd EasyTdd. Generators Nuget প্যাকেজের উপর নির্ভরতা ছাড়াই সম্পূর্ণ বিল্ডার কোড জেনারেশন অফার করে। আপনি যদি না চান বা তৃতীয় পক্ষের লাইব্রেরির উপর নির্ভর করতে না চান তবে এটি কার্যকর। এক্সটেনশনটি কোড তৈরি করে এবং সবই আপনার প্রজেক্টে, কোনো নির্ভরতা ছাড়াই, কোনো স্ট্রিং সংযুক্ত নেই। নির্দ্বিধায় সংশোধন করুন সব আপনার। এই পদ্ধতিটি EasyTdd.Generators কেসের সমস্ত সুবিধা প্রদান করে, টার্গেট ক্লাস পরিবর্তনের জন্য স্বয়ংক্রিয় পুনর্জন্ম ছাড়া।


এই ক্ষেত্রে, নির্মাতাকে ম্যানুয়ালি (কয়েকটি ক্লিকের সাথেও) পুনর্জন্ম করতে হবে। পুনর্জন্মের সময় সেটআপগুলি হারানোর জন্য দুটি ফাইল তৈরি করা হয়। একটি ফাইলে সমস্ত প্রয়োজনীয় পদ্ধতি সহ বিল্ডার শ্রেণীর ঘোষণা রয়েছে, অন্যটি কেবলমাত্র সেটআপ এবং অতিরিক্ত পদ্ধতির জন্য উদ্দেশ্যে করা হয়েছে, যা পুনর্জন্মের উদ্দেশ্যে নয়। দ্রুত অ্যাকশন মেনু খুলে "জেনারেট বিল্ডার" এ ক্লিক করে ক্লাসটি উপরের মতো একইভাবে তৈরি করা যেতে পারে:

যখন বিল্ডার ইতিমধ্যেই তৈরি হয় তখন টুলটি বিল্ডার ক্লাস খুলতে বা পুনরুত্থিত করার প্রস্তাব দেয়:

সারাংশ

এই ব্লগ পোস্টে, আমি বিল্ডার প্যাটার্ন এবং পরীক্ষা-চালিত উন্নয়নে এর ব্যবহার চালু করেছি। আমি বোগাস.ফেকার এবং এনবিল্ডারের মতো তৃতীয়-পক্ষের লাইব্রেরিগুলি ব্যবহার করে, বিল্ডারজেনারেটর এবং ইজিটিডিডি জেনারেটরস.বিল্ডার এবং শেষ পর্যন্ত, ইজিটিডিডি ভিজ্যুয়াল স্টুডিও দ্বারা তৈরি সমস্ত কোডের মতো ক্রমবর্ধমান কোড জেনারেটরগুলি ব্যবহার করে ম্যানুয়াল বাস্তবায়ন থেকে শুরু করে এটি বাস্তবায়নের বিভিন্ন উপায়ও দেখিয়েছি৷ এক্সটেনশন প্রতিটি পদ্ধতির তার শক্তি এবং দুর্বলতা রয়েছে এবং সাধারণ ক্ষেত্রে ভাল কাজ করে।


যাইহোক, অপরিবর্তনীয় শ্রেণীগুলির সাথে ডিল করার সময়, EasyTdd সম্পত্তির পরিবর্তনগুলিকে সমানভাবে পরিচালনা করার মাধ্যমে আলাদা হয়, সেটার দ্বারা বা একটি কনস্ট্রাক্টর প্যারামিটারের মাধ্যমে একটি সম্পত্তির মান শুরু করা হয়। EasyTdd টেমপ্লেট সমর্থন করে এবং আপনাকে আপনার পছন্দের সাথে মেলে আউটপুট কাস্টমাইজ করতে দেয়। EasyTdd বাস্তবায়নের গতির কারণে একজন নির্মাতাকে বাস্তবায়নের অন্যান্য পদ্ধতিকেও ছাড়িয়ে যায়। এটি ভিজ্যুয়াল স্টুডিওতে কিছু ক্লিকের মাধ্যমে স্বয়ংক্রিয়ভাবে ফাইল তৈরি করার জন্য সরঞ্জাম সরবরাহ করে, সময় এবং শ্রম সাশ্রয় করে।


আনস্প্ল্যাশে মার্কাস স্পিসকের ছবি