Skip to content

Commit

Permalink
updated unit testing hosted services
Browse files Browse the repository at this point in the history
  • Loading branch information
abdulrahmanshabeekmohamed committed Dec 13, 2024
1 parent a04e6df commit 2df0e4d
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 65 deletions.
2 changes: 1 addition & 1 deletion CommonComponents/wwwroot/atom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@
<link>https://ilovedotnet.org/blogs/unit-testing-hosted-services-in-asp-net-webapi</link>
<guid isPermaLink="true">https://ilovedotnet.org/blogs/unit-testing-hosted-services-in-asp-net-webapi</guid>
<description>In this post I will teach how to unit test hosted services in ASP.NET web api. All with live working demo.</description>
<pubDate>Sun, 13 Aug 2023 22:30:00 +0530</pubDate>
<pubDate>Sun, 15 Dec 2024 22:30:00 +0530</pubDate>
</item>
<item>
<title>Improving performance and memory use while accessing APIs using HTTPClient in dotnet</title>
Expand Down
2 changes: 1 addition & 1 deletion SharedModels/WebAPILearningPath.cs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ public WebAPILearningPath()
Channel = "WebAPI",
Type = "blogs",
CreatedOn = new DateTime(2023, 8, 13, 22, 30, 0, DateTimeKind.Utc),
ModifiedOn = new DateTime(2023, 8, 13, 22, 30, 0, DateTimeKind.Utc),
ModifiedOn = new DateTime(2024, 12, 15, 22, 30, 0, DateTimeKind.Utc),
Keywords = ["Unit Test", "Hosted Service", "Background Service"]
},
new ContentMetaData
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,123 +3,91 @@

<Content FileName=@nameof(UnitTestingHostedServicesInASPNET)>
<ContentBody>
<p>
In this article, let's learn about how to unit test <ContentHighlight>Hosted Services</ContentHighlight> in <ContentHighlight>WebAPI</ContentHighlight> in ASP.NET Core.
</p>

<p>
<strong>Note:</strong> If you have not done so already, I recommend you read the article on
<NavLink class="[ underline ]" href="blogs/perform-background-workloads-in-hosted-service-using-channels-in-asp-net-webapi" Match="NavLinkMatch.All">Perform Background Workloads in Hosted Service using Channels in ASP.NET Web API</NavLink>.
</p>

<h3 class="[ font-semibold text-lg ]">Table of Contents</h3>
<h3>Table of Contents</h3>

<ol class="[ list-decimal ] [ ml-4 ]">
<ol>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#introduction")" Match="NavLinkMatch.All">
Introduction
<NavLink href="@($"blogs/{Slug}#what")" Match="NavLinkMatch.All">
What we gonna do?
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#why-unit-testing")" Match="NavLinkMatch.All">
Why Unit Testing?
<NavLink href="@($"blogs/{Slug}#why")" Match="NavLinkMatch.All">
Why we gonna do?
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#what-is-a-hosted-service")" Match="NavLinkMatch.All">
What is a Hosted Service?
<NavLink href="@($"blogs/{Slug}#how")" Match="NavLinkMatch.All">
How we gonna do?
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#unit-testing-hosted-service")" Match="NavLinkMatch.All">
Unit Testing Hosted Service
</NavLink>
</li>
<li>
<NavLink class="[ underline ]" href="@($"blogs/{Slug}#summary")" Match="NavLinkMatch.All">
<NavLink href="@($"blogs/{Slug}#summary")" Match="NavLinkMatch.All">
Summary
</NavLink>
</li>
</ol>

<h3 id="introduction" class="[ font-semibold text-lg ]">Introduction</h3>
<h3 id="what">What we gonna do?</h3>

<p>
In this article, let's learn about how to unit test <ContentHighlight>Hosted Services</ContentHighlight> in <ContentHighlight>WebAPI</ContentHighlight> in ASP.NET Core.
</p>

<p>
In ASP.NET Core, <ContentHighlight>hosted services</ContentHighlight> plays a vital role in simplifying background jobs which needs to run periodically
to perform operations. Most common use cases include:
</p>

<ul class="[ ml-4 ] [ list-disc ]">
<ul>
<li><ContentHighlight>Processing uploaded excel in background</ContentHighlight></li>
<li><ContentHighlight>Sending emails in background</ContentHighlight></li>
<li><ContentHighlight>Performing data migration</ContentHighlight></li>
<li><ContentHighlight>Syncing data between two data sources</ContentHighlight></li>
<li><ContentHighlight>Other long running operations</ContentHighlight>, etc</li>
</ul>

<p>
If you are aware of <ContentHighlight>Hosted Service</ContentHighlight> and <ContentHighlight>Unit Testing</ContentHighlight> then you can skip the
next two sections and jump to the section on <ContentHighlight><NavLink class="[ underline ]" href="@($"blogs/{Slug}#unit-testing-hosted-service")" Match="NavLinkMatch.All">Unit Testing Hosted Service</NavLink></ContentHighlight>.
To know more about <ContentHighlight>Hosted Service</ContentHighlight> or <ContentHighlight>Background Service</ContentHighlight> is outside the scope
of this article. I'll write a separate article on Background Services in ASP.NET Core. For now lets understand walkthrough how to use Hosted Service.
</p>



<h3 id="why-unit-testing" class="[ font-semibold text-lg ]">Why Unit Testing ?</h3>
<h3 id="why">Why we gonna do?</h3>

<p>
When writing software, we want to ensure that the code is covered by tests, which verify the required behavior and catch any regressions.
<ContentHighlight>Unit testing</ContentHighlight> is a crucial practice in software development as it helps identify issues early in the development
process. When it comes to service registration, unit testing offers the following benefits:
</p>

<ul class="[ list-disc ] [ ml-4 ]">
<ul>
<li><ContentHighlight>Validation</ContentHighlight>: Unit tests verify that the necessary services are registered correctly, avoiding runtime errors caused by missing or misconfigured dependencies.</li>
<li><ContentHighlight>Refactoring</ContentHighlight>: Unit tests provide a safety net when refactoring code by ensuring that service registration remains intact during code changes.</li>
<li><ContentHighlight>Documentation</ContentHighlight>: Well-written unit tests serve as living documentation, illustrating how services should be registered and ensuring consistency across the application.</li>
</ul>

<p>
<strong>Note:</strong> If you have not done so already, I recommend you read the article on
<NavLink class="[ underline ]" href="blogs/implementing-tdd-in-csharp-dotnet" Match="NavLinkMatch.All">Implementing TDD in C# .Net</NavLink>.
<NavLink href="blogs/implementing-tdd-in-csharp-dotnet" Match="NavLinkMatch.All">Implementing TDD in C# .Net</NavLink>.
</p>



<h3 id="what-is-a-hosted-service" class="[ font-semibold text-lg ]">What is a Hosted Service ?</h3>

<p>
<ContentHighlight>Hosted services</ContentHighlight> in ASP.NET Core have been available since <ContentHighlight>version 2.1</ContentHighlight>, and
they support <ContentHighlight>performing background tasks outside of the main requests flow</ContentHighlight>. The best way to understand when and
where hosted services can be applied is to begin using them. Hosted services are based on the <ContentHighlight>abstract</ContentHighlight> concept
of a <ContentHighlight>background service</ContentHighlight>. The terms <ContentHighlight>hosted service</ContentHighlight> and
<ContentHighlight>background service</ContentHighlight> are often used interchangeably. I'll refer to them by both names throughout this article. Hosted services are available under
<ContentHighlight CssClasses="[ break-all ]">Microsoft.Extensions.Hosting</ContentHighlight> namespace.
</p>

<p>
To know more about <ContentHighlight>Hosted Service</ContentHighlight> or <ContentHighlight>Background Service</ContentHighlight> is outside the scope
of this article. I'll write a separate article on Background Services in ASP.NET Core. For now lets understand walkthrough how to use Hosted Service.
</p>



<h3 id="unit-testing-hosted-service" class="[ font-semibold text-lg ]">Unit Testing Hosted Service</h3>
<h3 id="how">How we gonna do?</h3>

<p>
We are going to write unit tests for the <ContentHighlight>Data Migration Hosted Service</ContentHighlight> which we used in our previous article on
<ContentHighlight><NavLink class="[ underline ]" href="blogs/perform-background-workloads-in-hosted-service-using-channels-in-asp-net-webapi" Match="NavLinkMatch.All">Perform Background Workloads in Hosted Service using Channels in ASP.NET Web API</NavLink></ContentHighlight>.
<ContentHighlight><NavLink href="blogs/perform-background-workloads-in-hosted-service-using-channels-in-asp-net-webapi" Match="NavLinkMatch.All">Perform Background Workloads in Hosted Service using Channels in ASP.NET Web API</NavLink></ContentHighlight>.
Here is the quick reference of the hosted service used in that article.
</p>

<GithubGistSnippet Title="Data Migration Hosted Service" UserId="fingers10" FileName="f066589f4d0439c6d02eade7ed08f537"></GithubGistSnippet>



<p>
To unit test the <ContentHighlight>DataMigrationService Hosted Service</ContentHighlight>, follow these steps:
</p>

<ol class="[ list-decimal ] [ ml-4 ]">
<ol>
<li>
Create a new test <ContentHighlight>class</ContentHighlight>, let's call it <ContentHighlight>HostedSrviceTests</ContentHighlight>, and add a test method
Create a new test <ContentHighlight>class</ContentHighlight>, let's call it <ContentHighlight>HostedServiceTests</ContentHighlight>, and add a test method
using the <ContentHighlight>[Fact]</ContentHighlight> attribute.
</li>
<li>
Expand Down Expand Up @@ -160,15 +128,58 @@

<GithubGistSnippet Title="Unit Testing Hosted Service in ASP.NET Web API" UserId="fingers10" FileName="78f22f4ba74f2655dc61e0440baca55b"></GithubGistSnippet>


<p>
Here is an another examples of background service using <ContentHighlight>PeriodicTimer</ContentHighlight> to Sync data. Let's see how to unit test this service.
</p>

<GithubGistSnippet Title="Data Syncing Hosted Service" UserId="fingers10" FileName="a1bb0b8c3996bdc6a3f0baa8bb695163"></GithubGistSnippet>

<p>
By executing above test we can validate background services in ASP.NET Core apps. The same can be used to validate worker services in dotnet.
To unit test the <ContentHighlight>DataSyncService Hosted Service</ContentHighlight>, follow these steps:
</p>


<ol>
<li>
Create a new test <ContentHighlight>class</ContentHighlight>, let's call it <ContentHighlight>HostedServiceTests</ContentHighlight>, and add a test method
using the <ContentHighlight>[Fact]</ContentHighlight> attribute.
</li>
<li>
In the test method, instantiate a <ContentHighlight>FakeTimeProvider</ContentHighlight> To adjust time and test. This is available from
<ContentHighlight CssClasses="[ break-all ]">Microsoft.Extensions.TimeProvider.Testing</ContentHighlight> namespace.
</li>
<li>
Finally let's use <ContentHighlight CssClasses="[ break-all ]">FakeLogger&lt;DataSyncService&gt;</ContentHighlight> from
<ContentHighlight CssClasses="[ break-all ]">Microsoft.Extensions.Diagnostics.Testing</ContentHighlight>
<ContentHighlight>namespace</ContentHighlight> instead of Mocking it as we are going to test the logger. Moreover mocking Logger is a
complex step.
</li>
<li>
Then, instantiate the <ContentHighlight>DataSyncService class</ContentHighlight> with the above instantiated parameters and call the
<ContentHighlight>StartAsync</ContentHighlight> method with <ContentHighlight>default CancellationToken</ContentHighlight> to start the service.
</li>
<li>
Now call <ContentHighlight>ExecuteTask</ContentHighlight> from the <ContentHighlight>DataSyncService</ContentHighlight> class to
execute the task. This will make the <ContentHighlight>ExecuteAsync</ContentHighlight> of actual background service to run.
</li>
<li>
Now adjust the time using by calling <ContentHighlight>Advance</ContentHighlight> from <ContentHighlight>FakeTimeProvider</ContentHighlight>.
This will execute the <ContentHighlight>SyncData callback</ContentHighlight> passed to the periodic timer in the
<ContentHighlight>DataSyncService</ContentHighlight> Background Service.
</li>
<li>
Perform <ContentHighlight>assertions</ContentHighlight> using the <ContentHighlight>IsCompletedSuccessfully</ContentHighlight> result on the
<ContentHighlight>ExecuteTask</ContentHighlight> of <ContentHighlight>DataSyncService</ContentHighlight>. Check for its success.
</li>
<li>Additionally, make assertions as per your needs.</li>
</ol>

<GithubGistSnippet Title="Unit Testing Hosted Service in ASP.NET Web API" UserId="fingers10" FileName="61c0b91ec1a5cd02a822d53330b58f03"></GithubGistSnippet>

<p>
By executing above test we can validate background services in ASP.NET Core apps. The same can be used to validate worker services in dotnet.
</p>

<h3 id="summary" class="[ font-semibold text-lg ]">Summary</h3>
<h3 id="summary">Summary</h3>

<p>
Unit testing hosted services in ASP.NET Core is a crucial step to ensure that they are working as expected. By writing unit tests, you can
Expand Down
2 changes: 1 addition & 1 deletion WebAPIDemoComponents/wwwroot/sitemap-blog-webapi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
</url>
<url>
<loc>https://ilovedotnet.org/blogs/unit-testing-hosted-services-in-asp-net-webapi</loc>
<lastmod>2023-08-13T22:30:00+05:30</lastmod>
<lastmod>2024-12-15T22:30:00+05:30</lastmod>
<changefreq>weekly</changefreq>
<priority>0.5</priority>
</url>
Expand Down

0 comments on commit 2df0e4d

Please sign in to comment.