Faking Dependencies in Functional testing in ASP.NET WEB API
WebAPI
19 Articles
In this article, let's learn about how to fake dependencies in Functional Test
in
WebAPI
in ASP.NET Core.
Note: If you have not done so already, I recommend you read the article on Functional testing your ASP.NET WEB API.
Table of Contents
Introduction
There are situations where we need to fake dependencies or replace services
in our Functional Test. We'll learn
about where to place the boundary
for integration tests and how this relates to the external
dependencies, such as a database, queues, etc
. And we'll create a fake for a dependency at that defined boundary.
Let's begin by creating a new test method named GetWeatherForecastFromDatabase
, and
we'll copy previous test to send the request and deserialize the response. So at this point, running the test results in a failure
.
Before we complete this test and its implementation, let's review the architecture of the API. We're building a cloud-native web API, so let's
imagine that we're going to use some cloud services such as a managed database.
Code Sample - Test to validate data from database
We have WeatherForecastDbContext
class in our API project. This is configured with
cloud connection string and registed in Program.cs
. We are going to inject this into our action method and read
the weather forecast data from database. I'm going to get into details of setting up DbContext
. I'll cover this
in my EntityFramework
Learning Path.
Why to Fake Dependencies ?
Rather than using services from our real cloud provider
in this article, which would complicate the setup to
follow along, it's good enough to use our imagination. When working with cloud providers, it's common to use language-specific SDKs that they supply
and maintain to code against their managed services. The implementations just hold the data in memory to mimic a real service, and that's sufficient
for this scenario.
The benefits of faking in functional tests include:
- Savings in
cost
. - Faster
time
to complete the test. Simple & Easy
to setup.
Therefore, lets fake these kind of dependencies.
Faking Database
In this example in our API, we are going to use EntityFramework
to connect to cloud database. We can fake the
database by using an in-memory sqlite
database provider to run our tests. Reason to use in memory sqlite
provider than in memory database is to make sure relation constraints are working as expected.
Add reference to
Microsoft.EntityFrameworkCore.Sqlite
andMicrosoft.Data.Sqlite
Nuget Package inFunctionalTest.csproj
.Add
static DatabaseHelper.cs
helper class toInitialize
andReset
Data for used in tests.Code Sample - Database Helper
-
Now we need to setup
IAsyncLifetime
usingSharedFixture
toInitialize
database only once for all tests. This is shown in the below code.Code Sample - Initialize Database only once using IAsyncLifeTime
-
Next we need to setup
CollectionDefinition
usingICollectionFixture<TFixture>
to make sure our fixture is initialized only once just before running first test in collection. This is shown in the below code.Code Sample - Initialize Fixture only once using ICollectionFixture<TFixture>
Finally we need to configure in memory sqlite db in
ConfigureServices
insideConfigureWebHost
tooverride
theService Registration
inCustomWebApiFactory
fromProgram.cs
.We need to find
WeatherForecastDbContext
andremove
and thencreate a sqlite in-memory connection and re-register WeatherForecastDbContext
with the sqlite in-memory connection. We can injectSharedFixture
to get Sqlite in memory database connection string. This is shown in the below code.Code Sample - Custom Web Application Factory
Thats it. We are done with setup. Now the tests will run in the following flow.
- Start Test Method.
- Create WebApplicationFactory.
- Run Program.cs.
- Service Registration.
- Overriding Service Registration with ConfigureServices.
- Build Web Application.
- Create HTTP Client.
- Test Code Execution.
Before we run the test, we need to modify BastTest
to expose DatabaseContext
to test methods to assert values from Database with API result. This is shown in the below code.
Code Sample - Expose DbContext in BaseTest
Now we need to decorate the test class with [Collection(nameof(FunctionalTestCollection))]
and modify the test as shown below to get values from database and assert it with API result as shown below. Lets run the test and see the result.
Code Sample - Decorate Test class with Collection attribure
Replacing Services
Now that we learnt how to fake database. We can also apply the same technique to replace services
in our
Functional Test
. Let's say we have a ExternalAPIService
service in our API which
implements IExternalAPIService
. We can replace this service with a
FakeExternalAPIService
service in our Functional Test
.
All we need to do is to find the ExternalAPIService
and remove
and then
create a FakeExternalAPIService
with expected output from that service and re-register
ExternalAPIService
with FakeExternalAPIService
.
This is shown in the below code.
But this way of replacing database or services will be difficult to maintain as we need to write a lot of code as replacement service for each scenario and test all scenarios. So I'll teach you another better way in next article.
Summary
In this article, we learnt about how to fake dependencies in Functional Test
in
WebAPI
in ASP.NET Core. We learnt about where to place the boundary
for
integration tests and how this relates to the external dependencies, such as a database, queues, etc
. This idea
can be extended and applied to any cloud based dependencies. In our next article, we'll learn about how to use TestContainers
in Functional Test
in WebAPI
in ASP.NET Core.