TheSharperDev

Educating about C# and F#

Unit Testing Giraffe's HttpHandlers in F#

 Photo by Sean Pollock on Unsplash

Please see git repo for working code example. Samuele Resca’s article on Testing F# Web Service was a great reference as I thought about unit testing Giraffe.

I’ve recently been playing around with Giraffe, “A native functional ASP.NET Core web framework for F# developers.” It sits on top of Microsoft’s ASP.NET Core, but provides a more functional way to interact with ASP.NET Core.

As someone who uses C# for work and learning F#, Giraffe felt like the right F# web framework to learn. I’ve been using the past couple weeks and wanted to share one way to unit test Giraffe HttpHandlers.

What are Handlers?

Here are a couple quotes from the Giraffe documentation.

The main building block in Giraffe is a so called HttpHandler:

Giraffe Docs

The easiest way to get your head around a Giraffe HttpHandler is to think of it as a functional equivalent to the ASP.NET Core middleware. Each handler has the full HttpContext at its disposal and can decide whether it wants to return Some HttpContext, None or pass it on to the “next” HttpFunc.

Giraffe Docs

Here is a very simple example of one:

So for me, handlers are the start of my application logic. I’m not going to dive deep into handlers, because this article is mainly about testing them. If you’re interested, the Giraffe docs do provide a good overview of how they’re used.

Unit Testing

The question I was wrestling with this week was how to unit test a handler. Here is a snippet of code to demonstrate my point:

We have a “fake db call”, our handler, then the route to direct the incoming request to our handler. The one thing that is limiting the testability of this handler is the db call on line 10. If I was going to unit test this method, it would make a database call. Which falls outside the scope of a unit test.

If this was C#, I would create an interface to hide that db call behind, then use a library like Moq to mock it. I could do something similar with Giraffe, because I have the ability to get services from the context. It works, I do it all the time when writing C#, but it’s not very functional.

I mentioned this to a friend and he suggested using another function to build my handler, that way I’m in control of what methods my handler is calling.

Handler Builder

Is there a way I can avoid hard coding that call in my handler?

To get a little meta, my handler doesn’t need a db call on line 10. My handler doesn’t know that dbUserInsert makes a database call. All my handler knows is that it gives some function an User and that function returns a Result<User, string>>. Then depending on whether that Result was Ok or Error, return the necessary response.

We leverage this fact and move that function from being called directly in my handler to be one of the function parameters.

You see line 7 no longer makes a db call, it just calls the insertUser parameter. Which when running our real code, would make a database call, but when unit test we would provide something testable.

Because we changed the type signature our handler, we need to introduce another function that curries our handler so it can respond to web requests.

The builder takes advantage of F#’s currying to apply the first parameter. The function now conforms to what a HttpHandler’s normal signature is, HttpFunc -> HttpContext -> Task<HttpContext option>. Now it can respond to web requests.

Unit Testing It

When unit testing, I can pass any function that matches that same signature.

On line 3, I create a “fake db call”, then pass that into my handler on line 7. Then I can test to make sure the result is what I’m expecting!

Final Thoughts

Learning F# and Giraffe is changing the way I think and program. As the title of this article mentions, this is just one strategy for unit tests handlers. Perhaps in the future I’ll find one I like better? Right now I’m happy writing code where I can manage my dependencies without going full interface/DI framework like I usually do in C#.

If you have any thoughts or comments, or know a better way to unit test Giraffe handlers please let me know!!!

Git Repo