Используя характеристики при тестировании процесс присвоения предлагает клиент


Я пытаюсь привести в порядок свои навыки БДД с использованием Specflow и огурчик. Смотрите уроки ниже:

public class Concor : IProduct
    {
        private const decimal _expenditure = 100;
        private const string _gender = "F";

        public bool IsEligible(Customer customer)
        {
            if (customer.Expenditure < _expenditure)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    public class Chestnut : IProduct
    {
        private const decimal _expenditure = 100;

        public bool IsEligible(Customer customer)
        {
            if (customer.Expenditure >= _expenditure)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }

    public interface IProduct
    {
        bool IsEligible(Customer customer);
    }

    public interface IOfferCalculator
    {
        //Passed a Customer object instead of Expenditure and Gender variables because these variables will be validated
        //in the customer class.
        IEnumerable<IProduct> CalculateEligibility(Customer customer, IList<IProduct> products);
    }

    public class Customer
    {
        public Guid Id { get; protected set; }
        public string Gender { get; protected set; }
        public decimal Expenditure { get; protected set; }
        public IList<IProduct> _assignedProducts = new List<IProduct>();

        public Customer(Guid id, string gender, decimal expenditure)
        {
            //Validation logic to go here.
            Id = id;
            Gender = gender;
            Expenditure = expenditure;
        }

        //Refactored this method to only accept one product
        public void AddOffer(IProduct eligibleProduct)
        {
            _assignedProducts.Add(eligibleProduct);
        }
    }


 public class OfferCalculator : IOfferCalculator
    {
        public IEnumerable<IProduct> CalculateEligibility(Customer customer, IList<IProduct> products)
        {
            foreach (var product in products)
            {
                if (product.IsEligible(customer))
                {
                    yield return product;
                }
            }
        }
    }

и характеристика файла ниже:

  • Характеристика: OfferCalculator

    • Для того, чтобы вычислить пригодность для гостей
    • Как калькулятор предложить я
    • хотите быть с учетом гендерных и расходов
  • Сценарий: право, когда дали пол мужской и расходования 101

    • Клиенту с пола мужчина и axpenditure из 101
    • И всем доступных продуктов
    • Когда я подсчитал права на продукты
    • Затем право на Конкор

и шаг определения ниже:

[Binding]
    public class OfferCalculatorSteps
    {
        private Customer _customer;
        private IOfferCalculator _offerCalculator;
        private List<IProduct> _availableProducts;
        private List<IProduct> _actualProduct;

        [Given(@"A customer with a gender of (.*) and an axpenditure of (.*)")]
        public void GivenACustomerWithAGenderOfMaleAndAnAxpenditureOf(string gender, int expenditure)
        {
            _customer = new Customer(Guid.NewGuid(), gender, expenditure);
            _offerCalculator = new OfferCalculator();
        }

        [Given(@"All available products")]
        public void GivenAllAvailableProducts()
        {
            _availableProducts = new List<IProduct>();
            _availableProducts.Add(new Concor());
            _availableProducts.Add(new Chestnut());
        }

        [When(@"I calculate eligibility for products")]
        public void WhenICalculateEligibilityForProducts()
        {
            _actualProduct= _offerCalculator.CalculateEligibility(_customer, _availableProducts).ToList<IProduct>();
        }

        [Then(@"Eligible for Concor")]
        public void ThenEligibleForConcor()
        {
            //Could use a Set here instead of a list.
            var expectedCreditCard = new List<IProduct>();
            expectedCreditCard.Add(_availableProducts.OfType<Chestnut>().Single());
            Assert.Equal(expectedCreditCard, _actualProduct);
        }
    }

Буду благодарен за комментарии касаемо качества данного Кодекса (а конкретно файл и шаг определения). Я специально стараюсь следовать принципу наименьшего удивления, так что когда другие разработчики подняться на борт; они могут забрать вещи quickily. Вот некоторые конкретные вопросы (хотя я специально прошу комментарии по поводу общего качества):

  1. Следует функции и шаг определения в их собственное пространство имен?

  2. Обратите внимание на сценарий говорит: "и все доступные продукты". Было бы лучше сказать: "и все имеющиеся товары: Конкор; Каштан". Я не вижу способ сделать это, как Конкор и Каштан классы.

  3. Я злоупотребляю использовать переменные экземпляра (у меня четыре переменные экземпляра в стадии определения)?

  4. Функция говорит: "как калькулятор предложение". Это не человек. Это нормально?

  5. Заметьте, что я сделал: expectedCreditCard.Добавить(_availableProducts.OfType<Chestnut>().Single());. это нормально?

  6. Обратите внимание на идентификаторы GUID, указанный в шаге определения. Это нормально?



170
1
задан 27 марта 2018 в 04:03 Источник Поделиться
Комментарии
2 ответа


Я специально стараюсь следовать принципу наименьшего удивления

и это


public IList<IProduct> _assignedProducts = new List<IProduct>();

не ладят. Открытое поле с _ подчеркивание? Я еще тогда удивился ;-)

Но не только этим. Если я могу получить доступ к этому полю напрямую, там на самом деле нет необходимости для меня, чтобы использовать этот метод:


public void AddOffer(IProduct eligibleProduct)
{
_assignedProducts.Add(eligibleProduct);
}

Было бы гораздо менее удивительно, если Customer класс реализован IEnumerable<IProduct> интерфейс... это тоже странно, что вы назвали метод AddOffer но аргумент IProduct.



public IEnumerable<IProduct> CalculateEligibility(Customer customer, IList<IProduct> products)
{
foreach (var product in products)
{
if (product.IsEligible(customer))
{
yield return product;
}
}
}

Вам придется пересмотреть этот дизайн. Вот еще один сюрприз. У заказчика есть набор продуктов, так почему я должна указывать оба параметра отдельно использовать CalculateEligibility? Не должно AddOfferили, вернее, AddProduct уже проверила? Другое дело, что этот метод ничего не высчитывает, он фильтрует товары по Право...

Я до сих пор не доволен этим, но, по крайней мере, нечто подобное было бы более приемлемо:

    public void AddProduct(IProduct product)
{
if(!product.IsEligible(this)) throw ...

_products.Add(product);
}

Поскольку продукт может сам проверить права OfferCalculator это совершенно не нужно... но это не если он сделал свою работу propertly, это проверка соответствия продукции в настоящее время. Тебе следует перенести эту логику туда, где она принадлежит и, видимо, он принадлежит к OfferCalculator.

5
ответ дан 27 марта 2018 в 04:03 Источник Поделиться

Коряво левой форматирование силы в целом

public class Concor : IProduct
{
private const decimal _expenditure = 100;
private const string _gender = "F";

public bool IsEligible(Customer customer)
{
if (customer.Expenditure < _expenditure)
{
return true;
}
else
{
return false;
}
}
}

Не использовать private const string _gender

Может просто return (customer.Expenditure < _expenditure);

Глупое название и может быть установлен в null.
public IList<IProduct> _assignedProducts = new List<IProduct>();

Я не собираюсь OfferCalculator как класс. Почему не статический метод?

products.where(x => c.IsEligible(customer))

1
ответ дан 27 марта 2018 в 04:03 Источник Поделиться