C# Interfaces Testability


This entry is part 3 of 8 in the series C# Interfaces

This post is based on Mosh Hamedani’s course at Udemy.com. It’s from his C# Intermediate course, section 6 on Interfaces, in the video called Interfaces and Testability. It is lengthy video with a fair amount of code to follow.

In this example we are going to see a hypothetical OrderProcessor. This object will take in an Order. Next we need to call the Process() method of the Order Processor and pass the Order to the method Processs(). We can see all of this in the Main() below. To process an order we need to calculate the shipping cost. We also need to save the date that the order was shipped. We have a business rule that says we always ship the next day. To calculate the shipping cost we use our object ShippingCalculator.

Program.cs

using System;
namespace InterfacesTestability
{
    class Program
    {
        static void Main(string[] args)
        {
            var orderProcessor = new OrderProcessor(new ShippingCalculator());
            var order = new Order { DatePlaced = DateTime.Now, TotalPrice = 100f };
            orderProcessor.Process(order);
        }
    }
}

OrderProcessor.cs

using System;
namespace InterfacesTestability
{
    public class OrderProcessor
    {
        private readonly IShippingCalculator _shippingCalculator;

        public OrderProcessor(IShippingCalculator shippingCalculator)  // constructor
        {
            _shippingCalculator = shippingCalculator;
        }
        public void Process(Order order)
        {
            if (order.IsShipped)  // defensive programming is good
                throw new InvalidOperationException("This order is already shipped");

            order.Shipment = new Shipment
            {
                Cost = _shippingCalculator.CalculateShipping(order),
                ShippingDate = DateTime.Today.AddDays(1)  // ship day after submitted
            };
        }
    }
}

Shipment.cs

using System;
namespace InterfacesTestability
{
    public class Shipment
    {
        public float Cost { get; set; }
        public DateTime ShippingDate { get; set; }
    }
}

ShippingCalculator.cs

namespace InterfacesTestability
{
    public interface IShippingCalculator
    {
        float CalculateShipping(Order order);
    }
    public class ShippingCalculator : IShippingCalculator  // this is NOT inheritance
    {  // we read this as ShippingCalculator implements IShippingCalculator
        // the cost of shipping depends on the value of the order
        public float CalculateShipping(Order order)
        {
            if (order.TotalPrice < 30f)
                return order.TotalPrice * 0.1f;
            return 0;
        }
    }
}

Order.cs

using System;
namespace InterfacesTestability
{
    public class Order
    {
        public Shipment Shipment { get; set; }
        public DateTime DatePlaced { get; set; }
        public float TotalPrice { get; set; }
        public bool IsShipped
        {
            get { return Shipment != null; }
        }
    }
}
Series Navigation<< C# Disposable ObjectsC# Interfaces Extensibility >>