update
One of the reasons that it's hard to find specific guidance in this area for OData, is that the URL resolution and OData Deserialization (especially around Patch
) is managed for us, or abstracted away. This is good and bad, but it means traditional API endpoint testing in isolation becomes complicated.
For instance a traditional API endpoint will have discrete input arguments and a discrete response argument, however OData arguments are generally wrapped inside generic dictionaries or helper objects that know how to manipulate queries based on their input but are hard to manually inspect. The response from an endpoint is also usually wrapped in a generic negotiated content response wrapper
Units tests should focus on behaviour only
Unit testing involves testing a part of an application in isolation from its infrastructure and dependencies. When you unit test controller logic, only the content of a single action or method is tested, not the behavior of its dependencies or of the framework itself. Unit tests do not detect issues in the interaction between components — that is the purpose of integration testing.
In the case of OData, query options like $filter
,$select
,$expand
... are really part of the framework, as is content negotiation and serialization. These elements require a lot of effort and configuration to mock for the purposes of a traditional unit test, so much so that many tests become indeterminate, when they pass or fail, is this related to the configuration or that actual logic that you were trying to target?
OData endpoints on the controller are generally easier to test using integration testing practises. Specifically for OData this means that you must run an instance of the actual service (either in memory, or deployed locally or to a specific test environment) so you can evaluate endpoints and how they evaluate query epressions through the HTTP pipeline.
You can automate this in VS, or do it in two steps, deploy your API to a testing location with a prepared database and then execute test scripts against it, either as VS unit tests or using external tools like Postman.
- There are NuGet packages that can help this process, but it is possible to "self host" your API programatically, so you can hook this up in the unit test init process.
These reasons complicate unit tests against OData endpoint methods directly:
- Much of the projection logic ($select/$expand) is evaluated by the
EnableQueryAttribute
- To construct an instance of ODataQueryOptions requires that the EdmModel is constructed and passed in as well as the Http request to operate on.
So the amount of effort required to setup your mocked QueryOptions is almost the same effort to just run an instance of the service.
If your test routine requires specific and complex manual configuration that basically recreates the API environment almost in full, then there is a high risk of false test results (positivites and negatives) when a test fails, does that mean that the setup for the test was faulty or that the production code you are testing is at fault?
Some people have had success in this area, have a look at this post in the OData Project forum:
[feature/netcore] How to unit test with ODataQueryOptions
#1352
Also have a look at this guidance, though it is less specific to your needs:
Unit test controller logic in ASP.NET Core