Owin.TestServer To Test a Middleware that Requires

2019-07-22 19:56发布

问题:

I have a middleware method that requires context.Authentication.User.Identity.Name to be resolved for proper execution. However, when writing a unit test these properties are obviously null as no sign-in has occurred. I am not using Oauth or anything authentication related in this middleware (beyond the obvious name property), as it should be handled elsewhere in another middleware (to promote re-use/flexibility of the component I am developing). Is there a way to mock/fake this value so I can run my test? I have tried everything I can think of to fake a sign-on and I am just stuck at this point. To be clear the middleware needs the value not a webapi call or the like.

//Arrange
var resolver = A.Fake<IDependencyResolver>();
A.CallTo(() => resolver.GetService(typeof(ISomeService))).Returns(new TestService());

using (var server = TestServer.Create(app =>
{
    app.UseMyMiddleware(new MyMiddlewareOptions()
    {
        DependencyResolver = resolver
    });

    app.Run(async ctx =>
    {
        await ctx.Response.WriteAsync(ctx.Request.Path.Value);
    });
}))
{
    //Act
    var response = await server.CreateRequest("/").GetAsync();

    //Assert
    A.CallTo(() => resolver.GetService(typeof(ISomeService)))
                           .MustHaveHappened(Repeated.Exactly.Once);
    Assert.AreEqual(response.StatusCode, HttpStatusCode.OK);
    //Etc.
}

回答1:

So here is one way I suppose not thrilled with it but it does the job. I will wait to accept as I imagine there should be a better way.

public class TestFakeLoginMiddleware : OwinMiddleware
{
    public TestFakeLoginMiddleware(OwinMiddleware next) : base(next)
    {
    }

    public override async Task Invoke(IOwinContext context)
    {
        var identity = A.Fake<IIdentity>();
        A.CallTo(() => identity.Name).Returns("TEST@domain.local");
        var user = new ClaimsPrincipal(identity);
        context.Request.Context.Authentication.User = user;
        await Next.Invoke(context);
    }
}


回答2:

A bit late, I know, but could you not just create a new ClaimsIdentity?

public override async Task Invoke(IOwinContext context)
{
    var identity= new ClaimsIdentity(new List<Claim> {
        new Claim(ClaimTypes.Name, "TEST@domain.local")
    });
    var user = new ClaimsPrincipal(identity);
    context.Request.Context.Authentication.User = user;
    await Next.Invoke(context);
}