И вот я вспомнил что мне где-то встечалось понятиe Behavior-Driven Development и тесты написанные в этом стиле намного читабельнее и понятнее. По запросу «nunit bdd» гугл выдает совсем немного результатов, но этот пост навел меня на интересную мысль. Методы Given и When не дают четкого описания условия и тем более описать больше чем одно условие наглядно не получится. Я решил слегка доработать решение.
Вот, кстати, то самое имя теста:
CreateMonthlyPaymentInvoice_WhenCustomerIsRegularCompany_ShouldCreateMonthlyUsageInvoiceWithoutBankFee.
Жутко, правда?
Я внес довольно незначительные изменения в подход, описанные в статье. Добавил атрибуты Given, And и When и логику вызова методов отмеченных этими атрибутами.
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), true).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 { } }
Теперь тесты стали намного более читабельными и гибкими.
[Specification] public class Create_invoice_for_regular_customer : SpecificationBase { private Customer _customer; private List<Transaction> _transactions; private XmlDocument _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 = "Jedy" } }; } [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(); } }
Если такая штука окажется полезной я попробую создать NuGet пакет для нее.
Спасибо за внимание тем, кто дочитал и хороших выходных.
ссылка на оригинал статьи http://habrahabr.ru/post/156325/
Добавить комментарий