public static void Main()
var testClass = new CarResidualValueCalculatorTests();
var methods = typeof(CarResidualValueCalculatorTests)
.GetMethods(BindingFlags.Public | BindingFlags.Instance)
.Where(m => m.GetCustomAttribute<TestAttribute>() != null);
foreach (var method in methods)
method.Invoke(testClass, null);
Console.WriteLine($"{method.Name}: Passed");
Console.WriteLine($"{method.Name}: Failed - {ex.InnerException?.Message}");
public interface IResidualValueCalculator
decimal CalculateResidualValue(decimal initialPrice, int age, decimal depreciationRate);
public class CarResidualValueCalculator : IResidualValueCalculator
public decimal CalculateResidualValue(decimal initialPrice, int age, decimal depreciationRate)
if (initialPrice < 0 || age < 0 || depreciationRate < 0 || depreciationRate > 1)
throw new ArgumentException("Invalid input parameters.");
return initialPrice * (decimal)Math.Pow(1 - (double)depreciationRate, age);
public class CarResidualValueCalculatorTests
private IResidualValueCalculator _calculator;
_calculator = new CarResidualValueCalculator();
public void CalculateResidualValue_ValidInput_ReturnsCorrectValue()
decimal initialPrice = 30000;
decimal depreciationRate = 0.10m;
decimal expectedResidualValue = 21870;
decimal actualResidualValue = _calculator.CalculateResidualValue(initialPrice, age, depreciationRate);
Assert.That(actualResidualValue, Is.EqualTo(expectedResidualValue).Within(0.01));
public void CalculateResidualValue_ZeroAge_ReturnsInitialPrice()
decimal initialPrice = 25000;
decimal depreciationRate = 0.15m;
decimal expectedResidualValue = 25000;
decimal actualResidualValue = _calculator.CalculateResidualValue(initialPrice, age, depreciationRate);
Assert.That(actualResidualValue, Is.EqualTo(expectedResidualValue).Within(0.01));
public void CalculateResidualValue_ZeroDepreciationRate_ReturnsInitialPrice()
decimal initialPrice = 40000;
decimal depreciationRate = 0m;
decimal expectedResidualValue = 40000;
decimal actualResidualValue = _calculator.CalculateResidualValue(initialPrice, age, depreciationRate);
Assert.That(actualResidualValue, Is.EqualTo(expectedResidualValue).Within(0.01));
public void CalculateResidualValue_NegativeInitialPrice_ThrowsArgumentException()
decimal initialPrice = -1000;
decimal depreciationRate = 0.05m;
Assert.Throws<ArgumentException>(() => _calculator.CalculateResidualValue(initialPrice, age, depreciationRate));
public void CalculateResidualValue_NegativeAge_ThrowsArgumentException()
decimal initialPrice = 35000;
decimal depreciationRate = 0.08m;
Assert.Throws<ArgumentException>(() => _calculator.CalculateResidualValue(initialPrice, age, depreciationRate));
public void CalculateResidualValue_NegativeDepreciationRate_ThrowsArgumentException()
decimal initialPrice = 28000;
decimal depreciationRate = -0.10m;
Assert.Throws<ArgumentException>(() => _calculator.CalculateResidualValue(initialPrice, age, depreciationRate));
public void CalculateResidualValue_DepreciationRateGreaterThanOne_ThrowsArgumentException()
decimal initialPrice = 32000;
decimal depreciationRate = 1.2m;
Assert.Throws<ArgumentException>(() => _calculator.CalculateResidualValue(initialPrice, age, depreciationRate));