Method Experiments

Method experiments allow you to organize a console lab's experiments into separate methods instead of placing all experiments in Main.

The following C# console lab could be improved. It runs 3 related experiments in Main without breaking them into separate methods.

using System;

namespace MyLabs
{
    public sealed class MathLab : BaseConsoleLab
    {
        protected override void Main()
        {
            var n = UserInputNumbers();
            TraceLine("{0} + {1} = {2}", n.Item1, n.Item2, n.Item1 + n.Item2);

            var n2 = UserInputNumbers();
            TraceLine("{0} * {1} = {2}", n2.Item1, n2.Item2, n2.Item1 * n2.Item2);

            var n3 = UserInputNumbers();
            TraceLine("{0} ^ {1} = {2}", n3.Item1, n3.Item2, n3.Item1 ^ n3.Item2);
        }

        private Tuple<int, int> UserInputNumbers()
        {
            return Tuple.Create(
                UserInputNumber("Enter the first number> "),
                UserInputNumber("Enter the second number> "));
        }

        private int UserInputNumber(string message)
        {
            int value;
            do
            {
                if (int.TryParse(UserInput(message), out value))
                {
                    return value;
                }
                else
                {
                    TraceError("Unrecognized value.  Please try again.");
                }
            }
            while (true);
        }
    }
}
Here's the output of this lab:

Starting Math Lab...

Enter the first number> 5
Enter the second number> 16
5 + 16 = 21
Enter the first number> 7
Enter the second number> 3
7 * 3 = 21
Enter the first number> 8
Enter the second number> 29
8 ^ 29 = 21

Math Lab Completed.

Notice that the experiments in Main are executed sequentially and the output does not distinguish between them. The user is also unable to cancel the lab between experiments.

Now here's the same lab again, but this time it's refactored so that experiments are located in separate public methods. Note the call to the base RunExperiments method in Main.

using System;

namespace MyLabs
{
    public sealed class MathLab : BaseConsoleLab
    {
        protected override void Main()
        {
            RunExperiments();
        }

        public void Add()
        {
            var n = UserInputNumbers();
            TraceLine("{0} + {1} = {2}", n.Item1, n.Item2, n.Item1 + n.Item2);
        }

        public void Multiply()
        {
            var n = UserInputNumbers();
            TraceLine("{0} * {1} = {2}", n.Item1, n.Item2, n.Item1 * n.Item2);
        }

        public void ExclusiveOr()
        {
            var n = UserInputNumbers();
            TraceLine("{0} ^ {1} = {2}", n.Item1, n.Item2, n.Item1 ^ n.Item2);
        }

        private Tuple<int, int> UserInputNumbers()
        {
            return Tuple.Create(
                UserInputNumber("Enter the first number> "),
                UserInputNumber("Enter the second number> "));
        }

        private int UserInputNumber(string message)
        {
            int value;
            do
            {
                if (int.TryParse(UserInput(message), out value))
                {
                    return value;
                }
                else
                {
                    TraceError("Unrecognized value.  Please try again.");
                }
            }
            while (true);
        }
    }
}
Here's the output of the improved lab:

Starting Math Lab...

Add (experiment 1 of 3)

Enter the first number> 5
Enter the second number> 16
5 + 16 = 21

Add (experiment 1 of 3) completed.

Press any key to start the next experiment or press Esc to stop...

Multiply (experiment 2 of 3)

Enter the first number> 7
Enter the second number> 3
7 * 3 = 21

Multiply (experiment 2 of 3) completed.

Press any key to start the next experiment or press Esc to stop...

ExclusiveOr (experiment 3 of 3)

Enter the first number> 8
Enter the second number> 29
8 ^ 29 = 21

ExclusiveOr (experiment 3 of 3) completed.

Math Lab Completed.

Notice that the lab automatically detects the experiments by calling the base RunExperiments method in Main. The lab still runs the experiments sequentially in Main, but now it prints the names of each experiment and the user is able to cancel the lab between experiments.

RunExperiments automatically gathers all public, parameterless, void-returning instance and static methods via reflection as individual experiments. Method experiments can optionally be marked with ExperimentAttribute and DescriptionAttribute to provide additional information. The base Experiments property can be overridden to specify experiments dynamically and to override the reflection mechanism.

Console labs for WPF, Silverlight and Windows Phone give the user the option to execute individual experiments directly. The following image shows the lab from the previous example in a WPF lab application. Notice that the drop-down list contains the individual experiments of the lab, allowing the user to select which experiment to run. The Main method is included as the first experiment.

MathLabWPF.png
WPF Lab showing the experiments drop-down list.

For more information, see Unit Experimentation.

Last edited Feb 7, 2012 at 3:32 PM by davedev, version 4

Comments

No comments yet.