📜 ⬆️ ⬇️

Create NUnit tests in BDD style

On a quiet Friday evening, I was finishing my work day by covering the implemented logic with tests. I carefully selected the names of the tests as Roy recommended. And suddenly I realized that the clear, detailed name of the test turned into a terrible monster and completely ceased to be understandable. And what's more, it no longer fits into 120 characters on the screen.

And so I remembered that the concept of Behavior-Driven Development and the tests written in this style were much more readable and understandable. On the query "nunit bdd" Google gives very few results, but this post brought me to an interesting idea. The Given and When methods do not give a clear description of the condition and, moreover, more than one condition cannot be clearly described. I decided to slightly modify the solution.

By the way, the very name of the test:
CreateMonthlyPaymentInvoice_WhenCustomerIsRegularCompany_ShouldCreateMonthlyUsageInvoiceWithoutBankFee.
Scary, right?

')
I made quite minor changes to the approach described in the article. Added the attributes Given, And and When and the logic of calling methods marked with these attributes.

namespace NUnit.Specification { public abstract class SpecificationBase { [TestFixtureSetUp] public void SetUp() { Setup(); Given(); When(); } public virtual void Setup() { } private void Given() { IEnumerable<MethodInfo> publicMethods = this.GetType().GetMethods(); publicMethods.Where(m => m.GetCustomAttributes(typeof(GivenAttribute), false).Count() != 0) .ToList() .ForEach(m => m.Invoke(this, new object[0])); publicMethods.Where(m => m.GetCustomAttributes(typeof(AndAttribute), false).Count() != 0) .ToList() .ForEach(m => m.Invoke(this, new object[0])); } private void When() { this.GetType() .GetMethods() .Where(m => m.GetCustomAttributes(typeof(WhenAttribute), false).Count() != 0) .ToList() .ForEach(m => m.Invoke(this, new object[0])); } [TestFixtureTearDown] public void TearDown() { Teardown(); } public virtual void Teardown() { } } public class SpecificationAttribute : TestFixtureAttribute { } public class GivenAttribute : Attribute { } public class AndAttribute : Attribute { } public class WhenAttribute : Attribute { } public class ThenAttribute : TestAttribute { } } 


Now the tests have become much more readable and flexible.

  [Specification] public class Create_invoice_for_regular_customer : SpecificationBase { private Customer _customer; private List<Transaction> _transactions; private Document _invoice; public override void Setup() { // General context setup like DateTimeProvider.Current = new Mock<DateTimeProvider>().Object; Mock.Get(DateTimeProvider.Current).Setup(m => m.GetCurrentTime()).Returns(new DateTime(2012, 10, 26)); } [Given] public void Customer_is_regular_company() { _customer= new Customer () { Name = "Jedi" }; } [And] public void Set_of_transactions_representing_monthly_usage() { _transactions = new[] { new Transaction() { Amount = 25 }, new Transaction() { Amount = 16 }, new Transaction() { Amount = 32 }, }.ToList(); } [When] public void Creating_monthly_usage_document() { _invoice = DocumentCreator.CreateMonthlyPaymentInvoice(_customer, _transactions); } [Then] public void Document_should_contain_transactions_and_not_contain_bank_fee() { var expectedInvoice = new ExpectedInvoice(); Assert.That(_invoice, Is.EqualTo(expectedInvoice)); } public override void Teardown() { DateTimeProvider.Current = new DateTimeProvider(); } } 


If such a thing turns out to be useful, I will try to create a NuGet package for it.
Thank you for your attention to those who read it and have a good weekend.

UPD: Randomly watching a video demo of Mighty Moose found that this idea was originally implemented in the example of Fohjin.DDD.Example . A little different, but the essence is the same. I can use several Given / And attributes in the same class.

Source: https://habr.com/ru/post/156325/


All Articles