nspec / NSpec

A battle hardened testing framework for C# that's heavily inspired by Mocha and RSpec.
http://nspec.org/
MIT License
260 stars 57 forks source link

Feature: Capture and rethrow errors into the "it"s #201

Open BennieCopeland opened 7 years ago

BennieCopeland commented 7 years ago

It would be nice to be able to do something like the following.

context["do something"] = () =>
{
    int someValue = int.MaxValue;
    MyClass myClass = null;

    beforeEach = () =>
    {
        myClass = new MyClass();
    };

    act = () => myClass.DoSomething(someValue);

    context["happy: value is good"] = () =>
    {
        beforeEach = () =>
        {
            someValue = 1;
        };

        it["will be happy"] = () =>
        {
            myClass.someValue.Should().Be(1);
        };
    };

    context["sad: value is bad"] = () =>
    {
        beforeEach = () =>
        {
            someValue = 256;
        };

        it["will throw an exception"] = expect<ArgumentOutOfRangeException>((exception) =>
        {
            exception.Message.Should().Be("You're an idiot!");
        });
    };
};

For singular cases, maybe something like this:

it["will throw an exception"] = expect<Exception>(() =>
{
    throw new Exception();
},
(exception) =>
{
    exception.Message.Should().Be("You're an idiot!");
});

I'm currently doing the following as a workaround, but a built in feature like above would be nice.

context["do something"] = () =>
{
    int someValue = int.MaxValue;
    MyClass myClass = null;
    bool expectException = false;
    Action action = null;

    beforeEach = () =>
    {
        myClass = new MyClass();
        expectException = false; // have to always set or it will screw up other contexts
    };

    act = () =>
    {
        action = () => myClass.DoSomething(someValue);
        if (!expectException) action();
    };

    context["sad: value is bad"] = () =>
    {
        beforeEach = () =>
        {
            someValue = 256;
        };

        it["will throw an exception"] = () =>
        {
            try
            {
                action();
            }
            catch(ArgumentOutOfRangeException ex)
            {
                ex.Message.Should().Be("You're an idiot!");
            }
        };
    };
};
BennieCopeland commented 7 years ago

I can try and find the time to create a PR for this over the next few weeks, but I was REALLY hoping the project had moved on from project.json. I don't look forward to reinstalling 2015.

amirrajan commented 7 years ago

@BennieCopeland there shouldn't be any "bare" code within the blocks. You need to put

int someValue = int.MaxValue;
MyClass myClass = null;
bool expectException = false;
Action action = null;

into the before.

BennieCopeland commented 7 years ago

@amirrajan That fails to build because the variables are now out of scope.

amirrajan commented 7 years ago

you have to make all your variables members of the test (class level).

BennieCopeland commented 7 years ago

That would work, but it could lead to a lot of variables at the class scope. I've never had a problem with scoping inside the contexts. But this is getting away from what this issue is about, which is a feature request for changing the exception handling behavior. Right now, context failures color the tests red (which is great), but I would like it to also hand the tests the caught exception for inspection.

amirrajan commented 7 years ago

But this is getting away from what the issue is about.

Yep sorry about that. Here is some food for thought: https://github.com/nspec/NSpec/issues/169

And this one: https://github.com/nspec/NSpec/issues/59