giraffe-fsharp / Giraffe

A native functional ASP.NET Core web framework for F# developers.
https://giraffe.wiki
Apache License 2.0
2.12k stars 266 forks source link

Question: How to approach outside in testing of a micro service? #575

Open dcook-net opened 9 months ago

dcook-net commented 9 months ago

Hi.

What is the best approach for outside in testing with Giraffe? Or am I bringing too much baggage with me from the OO world, and the preferred FP way is to do something else instead?

Context:

I'm coming to F# from C# and MVC and writing micro services.

I usually prefer testing these services from the outside (Use the Test Server to create a http client bound to the service under test, and making http calls to that service, asserting the expected response), as this allows loose coupling of the tests from the service, and allows for aggressive refactoring of the service internals if required, w/o the need to refactor the tests. I do utilise more low level unit style testing if and when required...it's just not my default behaviour.

Often, when the service I maintain makes an outbound request to a separate downstream service, the above test strategy is achieved by injecting a delegating handler into the HTTP client that will make the request, and that handler intercepts the outgoing call, returning a stubbed response. I am then able to confim the behaviour of my own service, based on how the downstream service behaves in a particular way: Ie; 200/ok on the happy path scenario, 5XX when the downstream times out or errors etc.

This delegating handler is injected into the HTTP Client during configuration of the TestServer/host, so is never injected into production code, only when the tests are running.

I've not been able to work out how to achieve this with F#. Not seen any examples of folks doing this. So I wondered if maybe this is not seen as the way of doing things in the FP world

64J0 commented 6 months ago

Hi @dcook-net, thanks for opening this issue. I think you can keep using this same strategy, just need to align it to the FP.

Imagine that you have an endpoint handler that depends on some external service. In this case, all you need to do is provide a different implementation for this service, based on the behavior you want to test (just change the function parameter/argument on your test suite).

If you're looking for some F# project that could help you to write the tests, please check https://github.com/haf/expecto.

64J0 commented 6 months ago

Just to be clear, when I said "align it to the FP" I meant that you must try to keep your functions as pure as possible, avoiding side effects. So, if it depends on a service, make it clear and add this service to the endpoint handler parameters. When you need to test this function later, just use the mocked service function.