Test helpers #1: Repetition Extensions and Scenario

While writing tons of tests I would like to share some of my helper classes here. My first ones are for doing simple performance measurements (not too accurate) and repeating actions.

Code:

using (new Scenario("Sum of all squares from 1 to 100"))
    Console.WriteLine("Sum is: {0}", 100.Times(x => x * x).Sum());

using (new Scenario("Print all squares from 1 to 10"))
    10.Times(x => Console.WriteLine("{0} * {0} = {1}", x, x*x));

Output:

>> {1} - Sum of all squares from 1 to 100
Sum is: 1000000
<< {1} 15ms for Sum of all squares from 1 to 100
>> {2} - Print all squares from 1 to 10
1 * 1 = 1
2 * 2 = 4
3 * 3 = 9
4 * 4 = 16
5 * 5 = 25
6 * 6 = 36
7 * 7 = 49
8 * 8 = 64
9 * 9 = 81
10 * 10 = 100
<< {2} 13ms for Print all squares from 1 to 10
&#91;/sourcecode&#93;</pre></div>

<h2>Repetition Extensions</h2>

<div style="display:inline;float:none;margin:0;padding:0;" id="scid:4CF65DF0-5960-450c-B43D-AE27EAE72175:64baee98-e9e4-4a96-9dc8-a453ac2997da" class="wlWriterEditableSmartContent"><pre>
public static class RepetitionExtensions
{
    public static IEnumerable<int> Times(this int count)
    {
        for (int i = 1; i <= count; i++)
        {
            yield return i;
        }
    }

    public static void Times(this int count, Action<int> action)
    {
        foreach (var i in count.Times())
        {
            action(i);
        }
    }

    public static void Times(this int count, Action action)
    {
        count.Times((i) => action());
    }

    public static TResult[] Times<TResult>(this int count, Func<TResult> action)
    {
        var results = new List<TResult>(count);
        count.Times(() => results.Add(action()));
        return results.ToArray();
    }

    public static TResult[] Times<TResult>(this int count, Func<int, TResult> action)
    {
        var results = new List<TResult>(count);
        count.Times(() => results.Add(action(count)));
        return results.ToArray();
    }

    public static IEnumerable<TResult> LazyTimes<TResult>(this int count, Func<TResult> action)
    {
        foreach (var i in count.Times())
        {
            yield return action();
        }
    }

    public static IEnumerable<TResult> LazyTimes<TResult>(this int count, Func<int, TResult> action)
    {
        foreach (var i in count.Times())
        {
            yield return action(i);
        }
    }
}

Scenario

public class Scenario : IDisposable
{
    private readonly string message;
    private readonly Stopwatch stopwatch = new Stopwatch();
    private static int nextUid = 0;
    private int uid = nextUid+=1;

    public Scenario(string message)
    {
        this.message = message;
        stopwatch = new Stopwatch();
        Console.WriteLine(">> {{{0}}} - {1}", uid, message);
        stopwatch.Start();
    }

    public void Dispose()
    {
        stopwatch.Stop();
        var elapsed = stopwatch.Elapsed;
        
        var elements = new List(4);

        if (elapsed.Days != 0)
            elements.Add(string.Format("{0} days", elapsed.Days));

        if (elapsed.Hours != 0)
            elements.Add(string.Format("{0} hours", elapsed.Hours));

        if (elapsed.Minutes != 0)
            elements.Add(string.Format("{0} minutes", elapsed.Minutes));

        if (elapsed.Seconds != 0 && elapsed.Milliseconds != 0)
            elements.Add(string.Format("{0}.{1}s", elapsed.Seconds, elapsed.Milliseconds));

        else if (elapsed.Seconds != 0)
            elements.Add(string.Format("{0}s", elapsed.Seconds));

        else if (elapsed.Milliseconds != 0)
            elements.Add(string.Format("{0}ms", elapsed.Milliseconds));

        var formatted = new StringBuilder();
        if (elements.Count > 0)
        {
            if (elements.Count > 1)
            {
                formatted.Append(string.Join(", ", elements.Take(elements.Count - 1).ToArray()));
                formatted.Append(" and ");
            }

            formatted.Append(elements.Last());
        }
            

        Console.WriteLine(string.Format("<< {{{0}}} {1} for {2}", uid, formatted, message));
    }
}
[/sourcecode]
Advertisements

3 thoughts on “Test helpers #1: Repetition Extensions and Scenario

  1. If you ask me you should just have Lazy version of the Times extensions. Always yield, the deferred execution is preferable and this is the way that all of the other linq extensions work, which is a + for consistency.

  2. Well,

    they are for testing purposes only. I have them only in the test code. And there, usually I want the actions to allways run all the times.

    Else you would end up with code like:

    10.Times(…).ToArray();

    Wouldn’t really be better, would it?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s