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"); }