1

I have a custom Nancy Bootstrapper which uses StructureMapNancyBootstrapper but the issue is the same regardless of container.

public class CustomNancyBootstrapper : StructureMapNancyBootstrapper
{
    protected override void RequestStartup(IContainer container, IPipelines pipelines, NancyContext context)
    {
        var auth = container.GetInstance<ICustomAuth>();
        auth.Authenticate(context);
    }
}

I want to write a test to assert that Authenticate is called with the context... something like this...

[Test]
public void RequestStartup_Calls_CustomAuth_Authenticate_WithContext()
{
    // set up
    var mockAuthentication = new Mock<ICustomAuth>();
    var mockContainer = new Mock<IContainer>();
    var mockPipelines = new Mock<IPipelines>();
    var context = new NancyContext();

    mockContainer.Setup(x => x.GetInstance<ICustomAuth>()).Returns(mockAuthentication.Object);

    // exercise
    _bootstrapper.RequestStartup(_mockContainer.Object, _mockPipelines.Object, context);

    // verify
    mockAuthentication.Verify(x => x.Authenticate(context), Times.Once);
}

The problem is that I can't call RequestStartup because it's protected as defined in NancyBootstrapperBase.

protected virtual void RequestStartup(TContainer container, IPipelines pipelines, NancyContext context);  

Is there a "proper"/"offical" Nancy way to do this without creating another derived class and exposing the methods as that just seems like a hack?

Thanks

alexs
  • 1,507
  • 18
  • 17

2 Answers2

1

I guess you can "fake" the request by using Browser from Nancy.Testing:

 var browser = new Browser(new CustomNancyBootstrapper());

 var response = browser.Get("/whatever");

There is a good set of articles about testing NancyFx application: http://www.marcusoft.net/2013/01/NancyTesting1.html

Anton Sizikov
  • 9,105
  • 1
  • 28
  • 39
  • Thanks for your response. I saw this but felt it was a little contrived as it's really testing the route and only testing the bootstrapper indirectly.. Still.. i think it's the best way forward so I'll mark as the answer. – alexs Nov 23 '15 at 09:22
  • yeah, I know. But they have a very active development on GitHub, I suggest you to fire up the issue https://github.com/NancyFx/Nancy/issues – Anton Sizikov Nov 23 '15 at 09:25
  • Thanks again Anton, I raised this issue which also has the actual code required to test via the 2 approaches above https://github.com/NancyFx/Nancy/issues/2126 – alexs Nov 23 '15 at 11:11
1

Turns out Nancy offers a IRequetStartup interface so you can take the code out of the custom bootstrapper and do something like this...

public class MyRequestStart : IRequestStartup
{
    private readonly ICustomAuth _customAuthentication;

    public MyRequestStart(ICustomAuth customAuthentication)
    {
        if (customAuthentication == null)
        {
            throw new ArgumentNullException(nameof(customAuthentication));
        }

        _customAuthentication = customAuthentication; 
    }

    public void Initialize(IPipelines pipelines, NancyContext context)
    {
        _customAuthentication.Authenticate(context);
    }
}

and the test is easy and concise

    [Test]
    public void When_Initialize_Calls_CustomAuth_Authenticate_WithContext()
    {
        // set up 
        var mockAuth = new Mock<ICustomAuth>();
        var requestStartup = new MyRequestStart(mockAuth.Object);
        var mockPipeline = new Mock<IPipelines>();
        var context = new NancyContext();

        // exercise
        requestStartup.Initialize(mockPipeline.Object, context);

        // verify
        mockAuth.Verify(x => x.Authenticate(context), Times.Once);
    }

https://github.com/NancyFx/Nancy/wiki/The-Application-Before%2C-After-and-OnError-pipelines#implementing-interfaces

alexs
  • 1,507
  • 18
  • 17