public async Task <List <BeneficiaryResponseModel> > CalculateBenefits(List <BeneficiaryRequestModel> request)
        {
            List <BeneficiaryResponseModel> response = new List <BeneficiaryResponseModel>();
            var tempBag = new ConcurrentBag <BeneficiaryResponseModel>();

            //Get constants for calulations - pay periods per year and discount percentage (fraction)
            decimal discount = await DataAccess.GetDiscountAsync();

            decimal payPeriods = await DataAccess.GetPayPeriodsAsync();

            //loop through the beneficiaries in the request and calculate costs for each one.
            //Adding simple parellism makes this a bit faster than a standard foreach - avg 1200ms vs 1600ms avg on a foreach
            IEnumerable <Task> tasks = request.Select(async b =>
            {
                BeneficiaryResponseModel beneficiary = new BeneficiaryResponseModel();

                //Trim the name to prevent issue with discount eligibility if name contains leading spaces
                beneficiary.Name   = b.Name.Trim();
                beneficiary.Type   = b.Type;
                decimal yearlyCost = await DataAccess.GetBenefitCostsAsync(b.Type);

                //Give the customer a discount if their name is eligible
                if (DiscountHandler.EligibleForDiscount(beneficiary.Name))
                {
                    yearlyCost *= (1 - discount);
                }

                beneficiary.YearCost   = yearlyCost;
                beneficiary.PeriodCost = decimal.Round((yearlyCost / payPeriods), 2);

                tempBag.Add(beneficiary);
            });

            await Task.WhenAll(tasks);

            //Convert the temporary concurrent bag to a list and store it in the response
            return(tempBag.ToList());
        }
        public async Task CalculateBenefits_GivenInput_ReturnsExpectedCosts()
        {
            //Arrange
            string  name1      = "Name1";
            string  name2      = "Name2";
            decimal discount   = 0.5M;
            int     payPeriods = 10;

            decimal employeeYearCost  = 400M;
            decimal dependentYearCost = 200M;

            decimal employeeDiscountYearCost  = (1 - discount) * employeeYearCost;
            decimal dependentDiscountYearCost = (1 - discount) * dependentYearCost;

            List <BeneficiaryRequestModel> testRequest = new List <BeneficiaryRequestModel>
            {
                new BeneficiaryRequestModel
                {
                    Name = name1,
                    Type = BenefitsData.Employee
                },
                new BeneficiaryRequestModel
                {
                    Name = name2,
                    Type = BenefitsData.Dependent
                }
            };

            BenefitCalculator calculator          = new BenefitCalculator();
            IDiscountHandler  fakeDiscountHandler = A.Fake <IDiscountHandler>();
            IDataAccessor     fakeDataAccess      = A.Fake <IDataAccessor>();

            calculator.DiscountHandler = fakeDiscountHandler;
            calculator.DataAccess      = fakeDataAccess;
            A.CallTo(() => fakeDiscountHandler.EligibleForDiscount(A <string> .Ignored)).Returns(true);
            A.CallTo(() => fakeDataAccess.GetBenefitCostsAsync(BenefitsData.Employee)).Returns(Task.FromResult(employeeYearCost));
            A.CallTo(() => fakeDataAccess.GetBenefitCostsAsync(BenefitsData.Dependent)).Returns(Task.FromResult(dependentYearCost));
            A.CallTo(() => fakeDataAccess.GetDiscountAsync()).Returns(Task.FromResult(discount));
            A.CallTo(() => fakeDataAccess.GetPayPeriodsAsync()).Returns(Task.FromResult(payPeriods));

            //Act
            var response = await calculator.CalculateBenefits(testRequest);

            //Assert
            A.CallTo(() => fakeDiscountHandler.EligibleForDiscount(name1)).MustHaveHappenedOnceExactly();
            A.CallTo(() => fakeDiscountHandler.EligibleForDiscount(name2)).MustHaveHappenedOnceExactly();
            A.CallTo(() => fakeDataAccess.GetDiscountAsync()).MustHaveHappenedOnceExactly();
            A.CallTo(() => fakeDataAccess.GetPayPeriodsAsync()).MustHaveHappenedOnceExactly();
            A.CallTo(() => fakeDataAccess.GetBenefitCostsAsync(BenefitsData.Employee)).MustHaveHappenedOnceExactly();
            A.CallTo(() => fakeDataAccess.GetBenefitCostsAsync(BenefitsData.Dependent)).MustHaveHappenedOnceExactly();

            BeneficiaryResponseModel expected1 = new BeneficiaryResponseModel
            {
                Name       = name1,
                Type       = BenefitsData.Employee,
                YearCost   = employeeDiscountYearCost,
                PeriodCost = decimal.Round((employeeDiscountYearCost / payPeriods), 2)
            };

            BeneficiaryResponseModel expected2 = new BeneficiaryResponseModel
            {
                Name       = name2,
                Type       = BenefitsData.Dependent,
                YearCost   = dependentDiscountYearCost,
                PeriodCost = decimal.Round((dependentDiscountYearCost / payPeriods), 2)
            };

            Assert.AreEqual(2, response.Count, "Expected the response to contain the same number of entries as input");

            var bene1 = response.Where(b =>
            {
                return(b.Name.Equals(expected1.Name) && b.Type.Equals(expected1.Type) && b.YearCost == expected1.YearCost && b.PeriodCost == expected1.PeriodCost);
            });

            var bene2 = response.Where(b =>
            {
                return(b.Name.Equals(expected2.Name) && b.Type.Equals(expected2.Type) && b.YearCost == expected2.YearCost && b.PeriodCost == expected2.PeriodCost);
            });

            Assert.AreEqual(1, bene1.Count(), "Expected the response to contain expected1 model");
            Assert.AreEqual(1, bene2.Count(), "Expected the response to contain expected2 model");
        }