dinsdag 13 december 2016

How to express an expected call on a Moq mock in the memberdata for an XUnit Theory.

In XUnit you can use the [Theory] attribute to run the same test against a set of different parameters. Moq allows you to specify expectations on which methods of a mocked interface are called, with the Verify method. Recently, I wanted to combine these two techniques to be able to convey the expectation along with the other test parameters to the XUnit Theory. It took me a little thought to get this right. The trick is in casting the expected call (usually an Action<T>) to an Expression<Action<T>>. That is done in the gist below.

dinsdag 11 oktober 2016

Simply check logged messages in .NET Core and Moq

The Microsoft.Extensions.Logging framework in ASP.NET Core is very useful for logging, but it can be somewhat verbose to check logged messages in your unit tests. Because the methods you use for logging (LogInformation, LogWarning etc.) are all extension methods, you cannot verify calls on them. You can verify calls to the Log method. But it took me some time to find out what the exact check should be. So I wrapped that knowledge into a utility method VerifyLog, in this Gist: Happy logging!

woensdag 20 juli 2016

ASP.NET Core Middleware pipeline 'Status code cannot be set, response has already started.'

ASP.NET Core has this beautiful concept of a pipeline of Middleware. See the introduction if you're not familiar with it.

In this tutorial you see you can always expect a 'next' to be available to invoke. But what if you have only one piece of middleware, or you are at the end of the pipeline? What is 'next' then?

The magic is in ApplicationBuilder, in the Build method:

1:      public RequestDelegate Build()  
2:      {  
3:        RequestDelegate app = context =>  
4:        {  
5:          context.Response.StatusCode = 404;  
6:          return Task.FromResult(0);  
7:        };  
8:        foreach (var component in _components.Reverse())  
9:        {  
10:          app = component(app);  
11:        }  
12:        return app;  
13:  }  

As you can see, a default RequestDelegate is appended to the end of the pipeline. It sets the StatusCode to 404 (meaning 'not found').

Now, where does the error in the title come from? It happens when you write to the httpContext.Response, and call next.Invoke(context). If none of the middleware components short-circuits the pipeline, eventually the 404 RequestDelegate above will be called. And that is where the problem starts: because you already started a response (leading to Response.HasStarted = true), you are not allowed to set the StatusCode anymore.

And what is the solution?


General rule of thumb: if you write to the Response in middleware X, end the pipeline (don't call next).

If you think about it this makes sense: X apparently knows the right response, so the request can be considered handled. Of course, the previous middleware components still get called on the way back through the pipeline. They also should not try to set the StatusCode.

Should you set the StatusCode yourself?


Not when the response is OK, because that is the default value of StatusCode. If your middleware decides that another response is appropriate, it should:
  • first set the StatusCode to an appropriate value (for example 201, Created)
  • then write to the Response
  • end the pipeline (don't call next)