Skip to content

Instantly share code, notes, and snippets.

@forki
Created February 19, 2011 18:01
Show Gist options
  • Save forki/835226 to your computer and use it in GitHub Desktop.
Save forki/835226 to your computer and use it in GitHub Desktop.
brainstorming for parameterized MSpecs
public class Math
{
public static int Fac(int x)
{
if (x <= 1)
return 1;
return Fac(x - 1)*x;
}
}
public class TestCaseList<T> : TestCaseList
{
readonly List<T> _data = new List<T>();
public TestCaseList<T> Add(T item)
{
_data.Add(item);
return this;
}
}
public static class Data
{
public static TestCaseList<T> Create<T>(T item)
{
return new TestCaseList<T>().Add(item);
}
public static TestCaseList<Tuple<T, S>> Create<T, S>(T x, S y)
{
return Create(Tuple.Create(x, y));
}
public static TestCaseList<Tuple<T, S>> Create<T, S>(this TestCaseList<Tuple<T, S>> list, T x, S y)
{
return list.Add(Tuple.Create(x, y));
}
}
public interface TestCaseList
{
}
public delegate TestCaseList TestData();
public delegate void Establish<in T>(T x);
public delegate void Establish<in T, in S>(T x, S y);
public class when_calculating_fac_of_ITEM1
{
static int x;
static int y;
static int result;
TestData data =
() =>
Data
.Create(1, 1)
.Create(2, 2);
Establish<int, int> context = (a,b) =>
{
x = a;
y = b;
};
Because of = () => result = Math.Fac(x);
It should_equal_ITEM2 = () => result.ShouldEqual(y);
}
@forki
Copy link
Author

forki commented Feb 19, 2011

Doesn't compile. Just an idea how it could look like.

@BjRo
Copy link

BjRo commented Feb 19, 2011

I like the idea to have the test data inline in the spec. However multiple problems with the syntax you've chosen:

a) You can't redefine the Establish, Because and It delegates. They are all of the type "void del()"
b) I don't think that all AAA steps need to or even should be parametrized. If you ask me, parametrization should only be done at the level of Establish. This however raises the question of how to do that without changing the Establish delegate. ;-( Just a quick thought, but I think that parametrization has to be outside of the scope of Establish in order to ensure backwards compatibility.
c)I don't think the generic type - parameters in the spec are necessary (or useful in this context for that for that matter)

This leaves us with your TestData. How about this:

public class when_calculating_fac
{
    static int result;

    Data<Tuple<int,int>> data = Data.Create(() =>
    {
        yield return Tuple.Create(1, 1);
        yield return Tuple.Create(2, 2);
        ...
    });

    Establish context = () => { ... };

    Because of = () => result = Fac(data.Current.Item1);

    It should_equal_the_fac = () => result.ShouldEqual(data.Current.Item2);
}

What do you think?

@BjRo
Copy link

BjRo commented Feb 19, 2011

Another think I would like to add to the parametrization mix, is encoding the parameters in the context / specification names. So that each run can be displayed as a separate spec in the report. Something like "Given_the_number_is_PARAM1_when_calculating_fac : should_return_RETURN1()"

@forki
Copy link
Author

forki commented Feb 20, 2011

Hi Björn,

thanks for the feedback. I added your suggestions and removed a little bit of noise. I think this could lead to something.

Regards,
Steffen

@BjRo
Copy link

BjRo commented Feb 22, 2011

I absolutely don't like the noise added by the generic Establish delegates:

Establish<int, int> context = (a,b) =>
{
x = a;
y = b;
};

Rest of the stuff looks good though. One point to mention about why I thought Data<> was a good idea. I wanted that information to be compile time visible so that it information about what type is contained can be extracted without having to execute the delegate. Would be nice for reporting (I guess ;-)).

Cheers
Björn

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment