Monday, September 27, 2010

Test Driven Approach - Positive Impact for Developers - Workshop III (Part A)

Quickly, we are now at 3rd session. Before we start, I would like to cover a bit on the missing architecture detail. This small application will be (hopefully) tailored into 3 layers design. UI, Core Logic, Data Access (if any). It is not that the requirements asking for so, it is simply some thought to have clear separation such that each component can be more tidy up with better cut of responsibility. Also, I hope I will have an opportunity in the future to bring this example into some further discussion on Scaling Out and Services Oriented fashion.


We have not create any data access layer assembly, but because we created a new assembly, "Core", hence a new Unit Test project for Core project is needed.

Enough said, now lets focus on the assignment. In reality, the calculator will be very unlikely to perform the calculation of such formula at once, "5 + 5% * 50 / 2 + pow(2,3)". Soon as you type in "5 + 5%", the calculator has already responded with the result. (Please verify with Windows Calculator). So, we will probably not cover this within this series of workshop.

Question: Where do we start coding to pass the test?
Answer: Let's start with the UI.

Question: How do we test the code in the UI?
Answer: We need a presenter or controller logic.

Calculator Presenter class develop as such: -
using System;
using System.Text;

namespace Calculator.Presenter
{
    public class Calculator
    {
        private readonly ICalculatorView _view;
        private readonly Core.Calculator _calculatorCore;

        public Calculator(ICalculatorView view)
        {
            _view = view;
            _calculatorCore = new Core.Calculator();
        }

        public void Evaluate()
        {
            _view.Result = _calculatorCore.Calculate(_view.Formula);
        }
    }

    public interface ICalculatorView
    {
        string Result { get; set; }
        string Formula { get; set; }
    }
}

This will need an additional Calculator class within the Core assembly as such: -
    public class Calculator
    {
        public string Calculate(string formula)
        {
            throw new NotImplementedException();
        }
    }

Now we sort of have everything (API) within this application that needs public access modifier done. We need to ensure the new public API sits under the Core project is unit tested as well. In this case, it is very similar to the earlier unit test created in Workshop II.

Next, we focus on how to wire up the UI into the presenter logic. This is what generated by VS 2010.
namespace Calculator
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            Application.Run(new CalculatorForm());
        }
    }
}

And here, we improve the sample WinForm class created during prototyping to utilize the presenter coded, as such: -
using System.Windows.Forms;
using Calculator.Presenter;

namespace Calculator
{
    public partial class CalculatorForm : Form, ICalculatorView
    {
        private Presenter.Calculator _calculator;

        public CalculatorForm()
        {
            InitializeComponent();
            _calculator = new Presenter.Calculator(this);
        }

        public string Result
        {
            get { return textBoxDisplay.Text; }
            set { textBoxDisplay.Text = value; }
        }

        public string Formula
        {
            get { return textBoxDisplay.Text; }
            set
            {
                textBoxDisplay.Text = value;
                textBoxDisplay.Refresh();
            }
        }
    }
}

Till this stage, we already have wire up most of the API needed within this application.

No comments:

Post a Comment