Question

I am studing NSpec framework.

Here is my example. I've written spec for a simple HttpRequester class:

using Moq;
using NSpec;

namespace FooBrowser.UnitTests.BDD
{
    class HttpRequester_specification : nspec
    {
        private HttpRequester requester;

        private string sentData;
        private int sendTimes;

        private readonly Mock<IConnection> connectionMock;
        private string resource;

        public HttpRequester_specification()
        {
            connectionMock = new Mock<IConnection>();

            connectionMock
                .Setup(x => x.Send(It.IsAny<string>()))
                .Callback<string>(data =>
                {
                    sendTimes++;
                    sentData = data;
                });
        }

        void given_opened_connection_with_no_recent_sends()
        {
            before = () =>
            {
                sendTimes = 0;
            };

            context["when HttpRequester is constructed"] = () =>
            {
                before = () => requester = new HttpRequester(connectionMock.Object);

                it["should not do any request"] = () => sendTimes.should_be(0);

                context["when performing request"] = () =>
                {
                    act = () => requester.Request(resource);

                    context["when resource is not specified"] = () =>
                    {
                        it["should do 1 request"] = () => sendTimes.should_be(1);
                        it["should send HTTP GET / HTTP/1.0"] = () => sentData.should_be("GET / HTTP/1.0");
                    };

                    context["when resource is index.html"] = () =>
                    {
                        before = () => resource = "index.html";

                        it["should do 1 request"] = () => sendTimes.should_be(1);
                        it["should send HTTP GET /index.html HTTP/1.0"] = () => sentData.should_be("GET /index.html HTTP/1.0");
                    };
                };
            };
        }
    }
}

As you can see it["should do 1 request"] = () => sendTimes.should_be(1); is written twice.

I try to move it to outer context like this:

context["when performing request"] = () =>
{
    act = () => requester.Request(resource);

    context["when resource is not specified"] = () =>
    {
        it["should send HTTP GET / HTTP/1.0"] = () => sentData.should_be("GET / HTTP/1.0");
    };

    context["when resource is index.html"] = () =>
    {
        before = () => resource = "index.html";

        it["should send HTTP GET /index.html HTTP/1.0"] = () => sentData.should_be("GET /index.html HTTP/1.0");
    };

    it["should do 1 request"] = () => sendTimes.should_be(1);
};

But this results to it["should do 1 request"] = () => sendTimes.should_be(1); is checked once for outer context, not for inner ones as I want.

So, can I move it to outer context somehow?

Or is it easier to contribute some code to NSpec to enable such behavior?

I found similar question here Reusing NSpec specifications but I want to keep lambda-expression syntax (with no inheritance) to see all specs in 1 place.

Was it helpful?

Solution

Sorry to see this is unanswered for two weeks, but I work around it simply by extracting a method like

void ItShouldRequestExactly(int n)
{
    it["should do " + n + " request"] = () => sendTimes.should_be(n);
}

This is DRY enough for me in most cases. You get however subtle problems when you pass in objects which are actually initialized at spec execution time, but for this simple example it fits perfectly. I sadly don't see another way to inject such mixin assertions into a context.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top