<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[.NET from the mountain]]></title><description><![CDATA[Rik van den Berg writing about .NET (Core), Microsoft Azure, Amazon Web Services and DevOps. My name translates to "fromthemountain" hence this blog's name.]]></description><link>https://dotnetfromthemountain.com/</link><image><url>https://dotnetfromthemountain.com/favicon.png</url><title>.NET from the mountain</title><link>https://dotnetfromthemountain.com/</link></image><generator>Ghost 5.62</generator><lastBuildDate>Sat, 11 Apr 2026 04:15:50 GMT</lastBuildDate><atom:link href="https://dotnetfromthemountain.com/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Azure CDN returns "InvalidUri" when using Terraform]]></title><description><![CDATA[The error was so vague and the fact that CDN changes take some time to propagate, it took me more effort than I wanted. So, here we are, I'm writing this blog post in the hopes of saving you some time. I ran into some connectivity errors when connecting an Azure CDN to an Azure blob storage.]]></description><link>https://dotnetfromthemountain.com/azure-cdn-returning-invaliduri/</link><guid isPermaLink="false">65f6cef71334f704857e9b51</guid><category><![CDATA[azure]]></category><category><![CDATA[cdn]]></category><category><![CDATA[blob]]></category><category><![CDATA[terraform]]></category><dc:creator><![CDATA[Rik van den Berg]]></dc:creator><pubDate>Sun, 17 Mar 2024 18:12:29 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1520869562399-e772f042f422?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fG5ldHdvcmt8ZW58MHx8fHwxNzEwNTk4MzA0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1520869562399-e772f042f422?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDd8fG5ldHdvcmt8ZW58MHx8fHwxNzEwNTk4MzA0fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform"><p>In hindsight, I could have probably solved this issue a lot quicker, but the error was so vague and the fact that CDN changes take some time to propagate, it took me more effort than I wanted. So, here we are, I&apos;m writing this blog post in the hopes of saving you some time. I ran into some connectivity errors when connecting an Azure CDN to an Azure blob storage. But this might also apply to your web apps.</p><p>TL;DR: <a href="#the-solution">Go to solution</a></p><h2 id="the-setup">The setup</h2><p>Our infrastructure setup is straightforward, centred around using Azure Blob Storage to host files like software installers, which are then distributed via Azure CDN to ensure global accessibility with low latency. A custom DNS was integrated with Azure CDN (and an Azure-managed SSL) to provide a branded and easy-to-remember access point for these files. The entire setup, from storage accounts to CDN configurations and custom DNS mapping, was provisioned and managed using Terraform. As a first setup, this is quite straightforward, and the terraform is relatively easy. It validates, plans and applies correctly, and even <a href="https://github.com/aquasecurity/tfsec?ref=dotnetfromthemountain.com">tfsec</a> didn&apos;t warn me about any errors. So we deployed the terraform with success. </p><pre><code class="language-tf">resource &quot;azurerm_resource_group&quot; &quot;downloads&quot; {
  name     = local.resource_group_name_with_location
  location = var.location
}

resource &quot;azurerm_storage_account&quot; &quot;downloads&quot; {
  name                     = local.escaped_random_name_24
  resource_group_name      = azurerm_resource_group.downloads.name
  location                 = var.location
  account_tier             = &quot;Standard&quot;
  account_replication_type = &quot;LRS&quot;
  min_tls_version          = &quot;TLS1_2&quot;
}

resource &quot;azurerm_cdn_profile&quot; &quot;resources&quot; {
  name                = &quot;${local.name}-cdn&quot;
  location            = var.location
  resource_group_name = azurerm_resource_group.downloads.name
  sku                 = &quot;Standard_Verizon&quot;
}

resource &quot;azurerm_cdn_endpoint&quot; &quot;resources&quot; {
  name                   = &quot;${local.name_with_suffix}-cdne&quot;
  profile_name           = azurerm_cdn_profile.resources.name
  location               = var.location
  resource_group_name    = azurerm_resource_group.downloads.name
  is_http_allowed        = false
  is_compression_enabled = true

  content_types_to_compress = [
    &quot;application/x-msdownload&quot; # For .exe files
  ]

  origin {
    name      = &quot;blob&quot;
    host_name = azurerm_storage_account.downloads.primary_blob_host
  }
}</code></pre><h2 id="the-problem">The problem</h2><figure class="kg-card kg-image-card"><img src="https://dotnetfromthemountain.com/content/images/2024/03/Error.png" class="kg-image" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform" loading="lazy" width="530" height="95"></figure><p>After it was provisioned we had to wait a couple of minutes, and sometimes a couple of hours while CDN got its configuration propagated. First, you will see HTTP 404 response and after a while, it should work. However, this was not the case. The error we were presented with was the following &quot;InvalidUri&quot; message.</p><pre><code class="language-xml">&lt;Error&gt;
	&lt;Code&gt;InvalidUri&lt;/Code&gt;
	&lt;Message&gt;The request URI is invalid. RequestId:bc46aeba-601e-0065-54b2-76b9e0000000 Time:2024-03-15T08:25:55.7419100Z
	&lt;/Message&gt;
&lt;/Error&gt;</code></pre><h3 id="diagnosis">Diagnosis</h3><p>So, first things first, we checked if the blob storage was working and if we could download the files using the storage account URL <code>***.blob.core.windows.net/downloads/installer.exe</code> and these were working just fine. So we can establish that the link between the CDN and the storage account is not correct. Thus I assumed a configuration error from my side. </p><h3 id="different-options">Different Options</h3><p>Another thing that didn&apos;t help to wrap my head around the problem is that there are multiple CDN options in Azure. Furthermore, everything has been consolidated in &quot;Azure Front Door and CDN profiles&quot;, so whenever you create one manually. The options are:</p><ul><li>Microsoft CDN (classic)</li><li>Microsoft Standard Edgio</li><li>Microsoft Premium Edgio</li><li>Microsoft Azure Front Door (more expansive and feature richt)</li></ul><p>So I tried all of these options, as you can manually create them from your blob storage. And obviously, these were working out of the box. &#x1F605;</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://dotnetfromthemountain.com/content/images/2024/03/image.png" class="kg-image" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform" loading="lazy" width="1175" height="854" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2024/03/image.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2024/03/image.png 1000w, https://dotnetfromthemountain.com/content/images/2024/03/image.png 1175w" sizes="(min-width: 720px) 720px"><figcaption>Create a CDN from your azure blob storage</figcaption></figure><p>Having identified that 1; there is a configuration error, and 2; it is most likely caused by the way we create the Azure CDN profiles, we can narrow down our search. My previous searches (and assistance of ChatGPT) didn&apos;t get a hit, but having identified Terraform as a potential configuration problem, I was able to narrow down the search.</p><h2 id="the-solution">The solution</h2><p>The problem is that the terraform template is missing the property <code>origin_host_header</code>. My next step would have been to manually compare the different endpoint configurations between the one created by Terraform and the one manually created, but I was able to find a Github issue with the same problem. It was one single property that I unfortunately overlooked. As you can see in the picture below, it is explained by inspecting this property in the Azure Portal that the Blob Storage and Web Apps require the <em>origin host header</em> to be specified. This is done for you when you manually create the CDN.<br>Thus, the correct terraform template should be like this for your CDN:</p><pre><code class="language-tf">resource &quot;azurerm_cdn_endpoint&quot; &quot;resources&quot; {
  name                   = &quot;${local.name_with_suffix}-cdne&quot;
  profile_name           = azurerm_cdn_profile.resources.name
  location               = var.location
  resource_group_name    = azurerm_resource_group.downloads.name
  is_http_allowed        = false
  is_compression_enabled = true

  content_types_to_compress = [
    &quot;application/x-msdownload&quot; # For .exe files
  ]

  # ORIGIN_HOST_HEADER is required for connecting with Web Apps, Blob Storage and Cloud Services
  origin_host_header = azurerm_storage_account.downloads.primary_blob_host
  origin {
    name      = &quot;blob&quot;
    host_name = azurerm_storage_account.downloads.primary_blob_host
  }
}

</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://dotnetfromthemountain.com/content/images/2024/03/image-2.png" class="kg-image" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform" loading="lazy" width="998" height="664" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2024/03/image-2.png 600w, https://dotnetfromthemountain.com/content/images/2024/03/image-2.png 998w" sizes="(min-width: 720px) 720px"><figcaption>Origin host header empty and thus cannot connect to your blob storage account.</figcaption></figure><h2 id="conclusion">Conclusion</h2><p>It felt a bit counterintuitive to link two properties to the primary blob host, but it is necessary for it to work. &#xA0;<br>I hope this post has helped you identify your problem working with Azure CDN and blob storage, provisioned by Terraform. However, I must give credit to F&#xE9;lix Prado as he was the one who was able to resolve this in his own Github issue.</p><h3 id="creditresources">Credit/Resources</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://felixprado.com/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">F&#xE9;lix Prado</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"></div></div><div class="kg-bookmark-thumbnail"><img src="https://felixprado.com/images/felixprado.jpg" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/hashicorp/terraform-provider-azurerm/issues/3084?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">CDN endpoint is not working when configured using Terraform &#xB7; Issue #3084 &#xB7; hashicorp/terraform-provider-azurerm</div><div class="kg-bookmark-description">Community Note Please vote on this issue by adding a &#x1F44D; reaction to the original issue to help the community and maintainers prioritize this request Please do not leave &#x201D;+1&#x2033; or &#x201C;me too&#x201D; comments, th&#x2026;</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/assets/pinned-octocat-093da3e6fa40.svg" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">hashicorp</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/74362341b6ec5ad40205ee59aace77ffd87cf6f5f902bfc6eeb7311ff1891247/hashicorp/terraform-provider-azurerm/issues/3084" alt="Azure CDN returns &quot;InvalidUri&quot; when using Terraform"></div></a></figure><p></p>]]></content:encoded></item><item><title><![CDATA[Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests]]></title><description><![CDATA[<p>Greetings once again, dear readers. It&apos;s been quite some time since my last entry, and I&apos;m delighted to resume our discussion. In this ongoing series on ASP.NET Core testing strategies, today marks the unveiling of our third installment.</p><p>In our previous post, we ventured into</p>]]></description><link>https://dotnetfromthemountain.com/aspnet-core-testing-strategies-integration-test/</link><guid isPermaLink="false">64137c8a4e2d8d152e469999</guid><category><![CDATA[asp.net core]]></category><category><![CDATA[integration test]]></category><category><![CDATA[component test]]></category><category><![CDATA[.net core]]></category><category><![CDATA[xUnit]]></category><category><![CDATA[testing]]></category><category><![CDATA[microservices]]></category><category><![CDATA[docker]]></category><category><![CDATA[container]]></category><dc:creator><![CDATA[Rik van den Berg]]></dc:creator><pubDate>Tue, 12 Sep 2023 20:48:31 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1583686298564-46fbffda0707?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDV8fGNvbnRhaW5lcnN8ZW58MHx8fHwxNjk0NjE0MDg5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1583686298564-46fbffda0707?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDV8fGNvbnRhaW5lcnN8ZW58MHx8fHwxNjk0NjE0MDg5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"><p>Greetings once again, dear readers. It&apos;s been quite some time since my last entry, and I&apos;m delighted to resume our discussion. In this ongoing series on ASP.NET Core testing strategies, today marks the unveiling of our third installment.</p><p>In our previous post, we ventured into the world of component tests, where we harnessed the power of TestDouble to replace HTTP calls and database interactions. If you happened to miss that piece, I highly recommend catching up, as it introduces a pivotal addition to your testing arsenal.</p><p>Now, let&apos;s turn our attention to the intriguing realm of integration tests. These tests serve as guardians, ensuring that your application interacts seamlessly with external components while upholding the integrity of your integration code. What sets this discussion apart is our incorporation of Docker, a tool that fortifies the robustness of the integration testing process.</p><p>But there&apos;s more in store for you. We&apos;ll also guide you through the seamless integration of these tests into your CI/CD pipeline, regardless of whether you prefer GitLab, GitHub Actions, or Azure Pipelines. So, stay with me as we embark on a comprehensive journey to integrate and test your ASP.NET Core applications with expertise and pragmatism.</p><blockquote>Integrations with data stores and external components benefit from the fast feedback of integration tests. Tests in this style provide fast feedback when refactoring or extending the logic contained within integration modules. However they also have more than one reason to fail &#x2014; if the logic in the integration module regresses <em>or</em> if the external component becomes unavailable or breaks its contract.<em> - <a href="http://github.com/tobyclemson?ref=dotnetfromthemountain.com" rel="author">Toby Clemson</a></em></blockquote><h2 id="when-to-use-integration-tests">When to use integration tests</h2><p>In the previous blog post, we have shown how we can use TestDoubles in order to test our components or microservices in isolation. We have seen that you can simply replace your database with an in-memory provider or replace your HTTP calls with a Mock in order to thoroughly acceptance test the behaviour. These component tests are low in build complexity and also execute relatively quickly. However, the thought of mocking entire external applications such as ElasticSearch with a TestDouble, is clearly too much work, and generally, these external applications come with the capability to run as a containerized version. So, in our XUnit unit tests, we are going to write some C# code, to startup some docker containers whenever we need one for an integration test. During some projects of mine, we used the following applications for integration tests: </p><ul><li><a href="https://hub.docker.com/_/elasticsearch/?ref=dotnetfromthemountain.com">ElasticSearch</a> (or <a href="https://hub.docker.com/r/opensearchproject/opensearch?ref=dotnetfromthemountain.com">OpenSearch</a> if you use AWS)</li><li><a href="https://hub.docker.com/r/amazon/dynamodb-local?ref=dotnetfromthemountain.com">AWS DynamoDb</a> </li><li><a href="https://hub.docker.com/_/microsoft-mssql-server?ref=dotnetfromthemountain.com">Microsoft SQL Server</a> or any other equivalen database provider such as Postgres, MongoDb, etc...</li></ul><h2 id="our-first-integration-test">Our first integration test</h2><p>So our requirements are simple. For each test we are running, there are a couple of steps we need to do.</p><ol><li><strong>Pull container: </strong>First we need to pull the docker image. This can either be done manually, in C# code or as part of a script in your CI/CD pipeline. In this blog I&apos;ll show you how to do it in code, but I would recommend the latter as this will help the execution speed of your builds and tests. Logically, once your test suite expands to 100&apos;s or 1.000&apos;s of tests, you don&apos;t want multiple tests competing to pull a container. </li><li><strong>Create container: </strong>Secondly, once we have pulled the container, we need to create the container before we can start it with the required parameters.</li><li><strong>Start container: </strong>Once created, we can start the container. Depending on the application you are running as a container, it might need some port binding configuration or environment variables.</li><li><strong>Run integration test:</strong> Then, everything is prepared to run our XUnit test. We run our (now called integration tests), but we configure additional settings and services for our ASP.NET Core application using the TestHost helpers we have seen in our previous blogs.<strong> </strong></li><li><strong>Cleanup:</strong> Finally, we need to cleanup our used containers. (Or not, one scenario we used was to reproduce a bug that we were not able to understand. By keeping the container, we could inspect the logs of the external application, in order to find the problem).</li></ol><p>To achieve all of this in code, Docker provides a <a href="https://github.com/dotnet/Docker.DotNet?ref=dotnetfromthemountain.com">NuGet package</a> for a .NET client to interact with your Docker daemon programmatically. And it would look something like this.</p><!--kg-card-begin: html--><script src="https://gist.github.com/rikvandenberg/f97aa01f4d4a2ff7bfe24a2758c98d7b.js"></script><!--kg-card-end: html--><p>But, this looks like a lot of work right? There is an easier way, but we&apos;ll get into that very soon. This code is just to demonstrate of all the steps that we need to do. In the next paragraphs we&apos;ll deep dive in making it more reusable by utilizing XUnit <code>IClassFixture</code> and we&apos;ll dive deeper into some more advanced scenarios</p><!--kg-card-begin: html--><div style="height: 40vmin;min-height: 360px"><script src="https://cdn.jsdelivr.net/ghost/signup-form@~0.1/umd/signup-form.min.js" data-background-color="#F1F3F4" data-text-color="#000000" data-button-color="#d4a259" data-button-text-color="#FFFFFF" data-title=".NET from the mountain" data-description="Rik van den Berg writing about .NET (Core), Microsoft Azure, Amazon Web Services and DevOps. My name translates to &quot;fromthemountain&quot; hence this blog&apos;s name." data-icon="https://dotnetfromthemountain.com/content/images/size/w192h192/size/w256h256/2021/02/11779470811558095024-512.png" data-site="https://dotnetfromthemountain.com" async></script></div><!--kg-card-end: html--><h2 id="xunit-and-docker-containers">XUnit and Docker Containers</h2><p>While the .NET client works great, it requires a lot of overhead in terms of code in order to write an integration test. Furthermore, in today&apos;s fast-paced software development landscape, efficiency and reproducibility are key. What we can do is to extract some of this code into a <a href="https://xunit.net/docs/shared-context?ref=dotnetfromthemountain.com">XUnit class fixtures</a>. This offers a powerful combination that can improve your testing workflow. With Docker containers as XUnit class fixtures, you can effortlessly set up and tear down isolated environments for your tests, ensuring consistency across different test runs and environments. This approach not only simplifies the process of managing dependencies but also enhances the portability of your test suite, making it easier to share and collaborate with team members.</p><p>While developing this approach in our team, we found two significant challenges. </p><ul><li>Firstly, in a larger parallel test suite, when tests require the same dockerized application, you can get conflicts. This can either be when querying for the same database or containers trying to reserve the same port. &#xA0;</li><li>Secondly, some containers have extended startup times of 20-30 seconds before it can be invoked by C# code. You can have a rudimentary solution as <code>Thread.sleep</code>, but this won&apos;t work relabily. We need to implement a container readiness checks, either custom or with Docker Compose health checks, ensuring that the container its services are operational before running the integration test. </li></ul><p>To make all these problems a bit more managable, we are going to use a different NuGet package, which is called <a href="https://dotnet.testcontainers.org/modules/?ref=dotnetfromthemountain.com">TestContainers</a>. And thus we can ensure smooth testing while harnessing the capabilities of Docker.</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://dotnet.testcontainers.org/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Testcontainers for .NET</div><div class="kg-bookmark-description"></div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://dotnet.testcontainers.org/favicon.ico" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"><span class="kg-bookmark-author">Menu</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://dotnet.testcontainers.org/language-logos/java.svg" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"></div></a></figure><h2 id="our-revised-integration-test">Our revised integration test</h2><p>Considering the above, your code could look somthing like this. We have made an abstract class called <code>ContainerFixture</code>, with the responsability to make sure our container automatically is started, stopped, and cleaned up. Then, we can make multiple implementations which focus on just specifying the container. As you can see, we make a <code>PostgresContainerFixture</code> which starts a postgress database for our orders API. This API is the one we have been using the last two posts.</p><!--kg-card-begin: html--><script src="https://gist.github.com/rikvandenberg/ea1722a357c63343581066a20a7c3121.js"></script><!--kg-card-end: html--><p>The second thing we need to do, is to update our integration test to configure either an URL or a connection string to the started container. This is quite similiar how we have already done this in our component test in our previous blog when we were using the Entity Framework in-memory solution.</p><!--kg-card-begin: html--><script src="https://gist.github.com/rikvandenberg/9460c174924b52355298c44dd3b9ab45.js"></script><!--kg-card-end: html--><p>And thus we can run our tests and inspect what is happening in the background during an integration test. Below in the screenshot you can see 3 containers being run. One is the <em>TestContainer</em> &quot;side car&quot;, which manages the containers during your tests. The two other containers are the postgres databases which are used by our integration tests that run in parallel. Here we can see and confirm that the Postgres port 5342 is randomly assigned on the host to prevent conflicts. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://dotnetfromthemountain.com/content/images/2023/09/image-1.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests" loading="lazy" width="1898" height="121" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2023/09/image-1.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2023/09/image-1.png 1000w, https://dotnetfromthemountain.com/content/images/size/w1600/2023/09/image-1.png 1600w, https://dotnetfromthemountain.com/content/images/2023/09/image-1.png 1898w" sizes="(min-width: 1200px) 1200px"><figcaption>The <code>docker ps</code> output during an integration test run where three containers are being started.&#xA0;</figcaption></figure><h2 id="waiting-for-elasticsearch-to-be-ready">Waiting for ElasticSearch to be ready</h2><p>Wonderful! Our test are running but there is more problems we need to address. As mentioned before, some containers take a while to startup (I&apos;m looking at you ElasticSearch &#x1F440;). Now in our case, we were doing even more complicated stuff. We had two applications which integrated with ElasticSearch. To make a long story short, we had one application writing the data, and another one responsible for reading and search. While settings this up, we of course ran into the forementioned problems of conflicts. But, we were able to write a big chunk of reusable code in order to load the data and prepare the integration test. &#xA0;</p><p>However, the main problem was waiting for the container to fully start. Since it was taking atleast 20-30 seconds, we didn&apos;t want to start a new container for every TestClass. This would add a lot of overhead, in terms of compute resources but also execution time. One thing we did was to ping the ElasticSearch healthcheck endpoint every 5 seconds, until we got back a green status. While rudamentry, it was working for us. Fortunately, TestContainers provides a number of prebuild containers and they have a much easier way to validate if the ES is ready to receive requests. Look at this <a href="https://dotnet.testcontainers.org/modules/?ref=dotnetfromthemountain.com">list of prebuild container builders</a> from <em>TestContainers. &#xA0;</em></p><p><sub>Azure Cosmos DB, Azure SQL Edge, Azurite, ClickHouse, Couchbase, CouchDb, DynamoDB, ElasticSearch, EventStoreDb, InfluxDB, K3s, Kafka, Keycloak, LocalStack, MariaDB, MinIO, MongoDB, MySQL, Neo4j, Oracle, PostgreSQL, RabbitMQ, RavenDB, Redis, Redpanda, SQL Server, WebDriver</sub> </p><p>So plenty to choose from! If you want a bit more control over your container, I would recommend writting some code of your own.</p><h2 id="continuous-integration">Continuous Integration</h2><p>Last but not least, we want to run all of this in our continuous integration/deployment tools in order to verify the behaviour of our application before we deploy them. To use TestContainers in your CI/CD environment, you only require Docker installed in your prefered agent. A local installation of Docker is not mandatory; you can also use a remote Docker installation. Below you&apos;ll find a couple of examples for three (or two if you look at it) different tools. TestContainers also prints some logs on what is happening. </p><h3 id="github">GitHub</h3><p><a href="https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&amp;ref=dotnetfromthemountain.com">Microsoft-hosted agents</a> come with Docker pre-installed, there is no need for any additional configuration. It is important to note that Windows agents use the Docker Windows engine and cannot run Linux containers. If you are using Windows agents, ensure that the image you are using matches the agent&apos;s architecture and operating system version. </p><figure class="kg-card kg-image-card"><img src="https://dotnetfromthemountain.com/content/images/2023/09/image-3.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests" loading="lazy" width="861" height="484" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2023/09/image-3.png 600w, https://dotnetfromthemountain.com/content/images/2023/09/image-3.png 861w" sizes="(min-width: 720px) 720px"></figure><!--kg-card-begin: html--><script src="https://gist.github.com/rikvandenberg/aa0aed50c24b1a3b6d04a9aa4d6ffc93.js"></script><!--kg-card-end: html--><h3 id="azure-pipelines">Azure Pipelines</h3><p>Both GitHub and Azure Pipelines use the same hosted build agents so the same remarks apply. </p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://dotnetfromthemountain.com/content/images/2023/09/image-5.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests" loading="lazy" width="1297" height="408" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2023/09/image-5.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2023/09/image-5.png 1000w, https://dotnetfromthemountain.com/content/images/2023/09/image-5.png 1297w" sizes="(min-width: 1200px) 1200px"></figure><h3 id="gitlab">GitLab</h3><p>And finally, to configure the Docker service in GitLab CI (<a href="https://docs.gitlab.com/ee/ci/docker/using_docker_build.html?ref=dotnetfromthemountain.com#use-docker-in-docker">Docker-in-Docker</a>), you need to define the service in your <code>.gitlab-ci.yml</code> file and expose the Docker host address <code>docker:2375</code> by setting the <code>DOCKER_HOST</code> environment variable. Below the output and the code.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://dotnetfromthemountain.com/content/images/2023/09/image-2.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests" loading="lazy" width="1295" height="91" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2023/09/image-2.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2023/09/image-2.png 1000w, https://dotnetfromthemountain.com/content/images/2023/09/image-2.png 1295w" sizes="(min-width: 1200px) 1200px"></figure><!--kg-card-begin: html--><script src="https://gist.github.com/rikvandenberg/d8683e74a0427eca95d5b83756de7758.js"></script><!--kg-card-end: html--><h2 id="conclusion">Conclusion</h2><p>In conclusion, our exploration of integration testing in ASP.NET Core has been enlightening. We&apos;ve seen how Docker can enhance these tests by simplifying dependency management and improving portability.</p><p>We&apos;ve also tackled common integration testing challenges, such as conflicts in parallel test suites and dealing with slow-starting containers, using the TestContainers NuGet package.</p><p>Additionally, we&apos;ve discussed how to integrate these tests into your CI/CD pipeline, ensuring your applications are thoroughly tested before deployment, whether you&apos;re using GitHub, Azure Pipelines, or other tools.</p><p>In the world of software development, mastering integration testing with Docker and TestContainers is essential for efficient and reliable application development. Armed with these insights, may your tests run smoothly, and your applications thrive. Happy coding!</p><div class="kg-card kg-callout-card kg-callout-card-purple"><div class="kg-callout-emoji">&#x1F4A1;</div><div class="kg-callout-text"><strong>I would love to hear if you been using this in your project or tried it out yourselves. Feel free to comment, reach out or subscribe to receive an email when I post new blogs. I&apos;ve got a couple more posts lined up that I want to do. One is about C# integration with AWS and localstack.</strong></div></div><!--kg-card-begin: html--><div style="height: 40vmin;min-height: 360px"><script src="https://cdn.jsdelivr.net/ghost/signup-form@~0.1/umd/signup-form.min.js" data-background-color="#F1F3F4" data-text-color="#000000" data-button-color="#d4a259" data-button-text-color="#FFFFFF" data-title=".NET from the mountain" data-description="Rik van den Berg writing about .NET (Core), Microsoft Azure, Amazon Web Services and DevOps. My name translates to &quot;fromthemountain&quot; hence this blog&apos;s name." data-icon="https://dotnetfromthemountain.com/content/images/size/w192h192/size/w256h256/2021/02/11779470811558095024-512.png" data-site="https://dotnetfromthemountain.com" async></script></div><!--kg-card-end: html--><h2 id="resources-credits">Resources/Credits</h2><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://m.do.co/c/da955a437503?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">DigitalOcean | Cloud Hosting for Builders</div><div class="kg-bookmark-description">Simple, scalable cloud computing solutions built for startups and small-to-midsize businesses.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://m.do.co/_next/static/media/apple-touch-icon.d7edaa01.png" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"><span class="kg-bookmark-author">Cloud Hosting for Builders</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.digitalocean.com/_next/static/media/social-share-default.e8530e9e.jpeg" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"></div></a><figcaption>Referral link to $200 free credits with digital ocean to try it out with 60 days</figcaption></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://martinfowler.com/articles/microservice-testing/?ref=dotnetfromthemountain.com#testing-integration-diagram"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Testing Strategies in a Microservice Architecture</div><div class="kg-bookmark-description">The microservice architectural style presents challenges for organizing effective testing, this deck outlines the kinds of tests you need and how to mix them.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://martinfowler.com/favicon.ico" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"><span class="kg-bookmark-author">martinfowler.com</span><span class="kg-bookmark-publisher">Toby Clemson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://martinfowler.com/articles/microservice-testing/meta-image.png" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/rikvandenberg/aspnetcore-component-tests/tree/part-3?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - rikvandenberg/aspnetcore-component-tests at part-3</div><div class="kg-bookmark-description">Contribute to rikvandenberg/aspnetcore-component-tests development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/pinned-octocat.svg" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">rikvandenberg</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/bd66959b111e833e60562d339c0324780593aa2bbdd78d42fff2ec12b4d47a85/rikvandenberg/aspnetcore-component-tests" alt="Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Different kinds of testing strategies with ASP.NET Core:  Component tests]]></title><description><![CDATA[Want to test ASP.NET Core applications in isolation that use HTTP clients and database integrations? Then read this blog about how to build small and isolated components tests that are aimed to run tests purely on your application code]]></description><link>https://dotnetfromthemountain.com/aspnet-core-testing-strategies-component-test/</link><guid isPermaLink="false">64137c8a4e2d8d152e469998</guid><category><![CDATA[asp.net core]]></category><category><![CDATA[component test]]></category><category><![CDATA[integration test]]></category><category><![CDATA[.net core]]></category><category><![CDATA[.net]]></category><category><![CDATA[testing]]></category><category><![CDATA[xUnit]]></category><category><![CDATA[microservices]]></category><dc:creator><![CDATA[Rik van den Berg]]></dc:creator><pubDate>Thu, 07 Oct 2021 11:31:49 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1532188363366-3a1b2ac4a338?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNvbXBvbmVudCUyMGxhcHRvcHxlbnwwfHx8fDE2MjY0MzkxMTM&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1532188363366-3a1b2ac4a338?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNvbXBvbmVudCUyMGxhcHRvcHxlbnwwfHx8fDE2MjY0MzkxMTM&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"><p>In <a href="https://dotnetfromthemountain.com/aspnet-core-testing-strategies-the-basics/">the previous post</a>, we looked at some of the basics steps for writing tests for our REST API in ASP.NET Core. We learned how to self-host our API, send HTTP requests to execute our test, customize logging to report details of these tests, and customize our settings. More specifically, we showed how to replace our external dependencies, such as a database, through dependency injection with an in-memory version that used a list. That post was a small preview of what is to come and what we will be addressing in this post. With the techniques from the previous post in place, we can run our application as deployed in a test without any external calls. By replacing these external calls with <a href="https://martinfowler.com/bliki/TestDouble.html?ref=dotnetfromthemountain.com">TestDoubles</a>, we start to create a boundary and isolate our API. These kinds of tests are more known as component tests. In this post, the second part of a three-part series, we will go into more depth about component tests. We will talk about:</p><ul><li>Introduction about component tests</li><li>Overview of NuGet packages we are using</li><li>Replacing integrations with TestDoubles</li></ul><p>We will go into depth about the kind of integrations we will be replacing with a TestDouble. All of this, we will do with the help of dependency injection. Some examples are:</p><ul><li>EntityFramework: Replace <code>DbContext</code> by using the in-memory versions</li><li>HTTP integration: Replace <code>HttpClient</code> with a special handler that simulates our requests.</li></ul><p>And finally, we will put all these examples together into a single component test. Let us get to it because there is a lot to discuss. </p><h3 id="introduction">Introduction</h3><p>To understand what we are going to do in this post, it is best to look at the definition of a component test. I very much like the <a href="https://martinfowler.com/articles/microservice-testing/?ref=dotnetfromthemountain.com">description and the presentation from Martin Fowler and Toby Clemson - Testing Strategies in a Microservice Architecture</a>. This post outlines everything about this topic. It serves as a precise definition, one that we will apply in our examples, and serves as a thread through our posts. I highly recommend reading it.</p><blockquote><em>A component test is a test that limits the scope of the exercised software to a portion of the system under test...where component tests deliberately neglect parts of the system outside the scope of the test. - Toby Clemson</em></blockquote><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://dotnetfromthemountain.com/content/images/2021/04/image-2.png" class="kg-image" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests" loading="lazy" width="744" height="479" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2021/04/image-2.png 600w, https://dotnetfromthemountain.com/content/images/2021/04/image-2.png 744w" sizes="(min-width: 720px) 720px"><figcaption><a href="https://martinfowler.com/articles/microservice-testing/?ref=dotnetfromthemountain.com#testing-component-in-process-diagram">https://martinfowler.com/articles/microservice-testing/#testing-component-in-process-diagram</a></figcaption></figure><p>Looking at the definition and the above image, we can quickly see the boundary of the component test. The goal of the component test is to limit the scope to only your code. It places any external parts, such as a database or an HTTP service, outside the system. But there could be many more moving pieces in your application. Some other examples we&apos;ve identified in our application are things like caches, files, streams, message publisher/subscribers, and many more. In practice, when writing these tests yourself, you&apos;ll have to identify these &quot;parts of the system&quot; that are outside of the scope of your test.</p><p>Once identified, we can look at the second part of the definition. This part is about &quot;neglecting&quot; these external dependencies. With the help of dependency injection (as you might have seen in the previous post), we will replace part of our code with a <a href="https://martinfowler.com/bliki/TestDouble.html?ref=dotnetfromthemountain.com">TestDouble</a>. But the question is, which classes do we have to replace? Let&apos;s take a look at the class structures. </p><figure class="kg-card kg-image-card"><img src="https://dotnetfromthemountain.com/content/images/2021/10/image-2.png" class="kg-image" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests" loading="lazy"></figure><p>As an example, take the above class diagram. Here we need to find the lowest level of integration to replace with dependency injection. You can see that the implementation of the <code>ShopifyProductsClient</code> has a dependency on the <code>HttpClient</code>. It uses this class to add additional headers such as an API key and makes sure the response is valid. Furthermore, this client is exposed through the abstraction of an interface called <code>IProductsService</code>. The implementation of this service is not at the lowest level. Suppose you replace the interface with a dummy implementation returning a single product. When doing so in your component test, you are only replacing part of your code and you are not really testing the implementation of the service. It would be better if you have a way to control the &#xA0;<code>HttpClient</code> and its respective requests and responses. This kind of control will allow you to <u>simulate</u> how an external API call such as Shopify responds. You can assert that your microservice adds the API key to the headers and handles the happy flow well. This method also allows you to test how your service responds resiliently to an HTTP 4XX or 5XX response. </p><h3 id="some-nuget-packages-are-we-using-">Some NuGet packages are we using...</h3><p><a href="https://github.com/Moq/moq4/wiki/Quickstart?ref=dotnetfromthemountain.com">Moq </a><br>Moq is a package that, in their own words, &quot;is intended to be simple to use, strongly typed (no magic strings!, and therefore full compiler-verified and refactoring-friendly) and minimalistic (while still fully functional!)&quot;. I&apos;ve worked with Moq for a very long time and it suits most of my needs when I need to inject an abstraction into my SystemUnderTest. Moq can serve both as a <u>Mock</u> and a <u>Spy </u>at the same time. On one side it requires you to set up your expectations for the class/interface that is being called and respond in a certain way. On the other side, it also allows you to verify invocations such as how many times it was called, with what parameters, etc, etc.</p><pre><code class="language-csharp">var mock = new Mock&lt;IFoo&gt;();

// basic example
mock.Setup(foo =&gt; foo.DoSomething(&quot;ping&quot;)).Returns(true);

// access invocation arguments when returning a value
mock.Setup(x =&gt; x.DoSomethingStringy(It.IsAny&lt;string&gt;()))
		.Returns((string s) =&gt; s.ToLower());

// throwing exceptions when invoked with specific parameters
mock.Setup(foo =&gt; foo.DoSomething(&quot;reset&quot;)).Throws&lt;InvalidOperationException&gt;();
mock.Setup(foo =&gt; foo.DoSomething(&quot;&quot;)).Throws(new ArgumentException(&quot;command&quot;));</code></pre><p><a href="https://github.com/AutoFixture/AutoFixture?ref=dotnetfromthemountain.com">AutoFixture</a><br>AutoFixture is a library that aims to simplify the setup for your tests. Generally speaking, when writing a unit test, you need to write some code to <em>arrange</em> some data. Complex objects like <code>Customer</code>, <code>Order</code> or maybe an even more complex structure. When you need large datasets or POCO&apos;s with a high number amount of properties, it is very tedious to set these tests up. I often write a factory class that has some logic to construct data for my domain. But when I&apos;m not interested in what the data is, I used AutoFixture.</p><pre><code class="language-csharp">[Fact]
public void IntroductoryTest()
{
    // Arrange
    Fixture fixture = new Fixture();
    Customer sut = fixture.Create&lt;Customer&gt;();
    
    // Act
    int result = sut.GetNumberOfOrders();
    
    // Assert
    Assert.Equal(expectedNumber, result);
}</code></pre><p><a href="https://github.com/richardszalay/mockhttp?ref=dotnetfromthemountain.com">MockHttp</a><br>MockHttp is a testing library for Microsoft&apos;s <code>HttpClient</code> class. It allows stubbed responses to be configured for pre-defined HTTP requests and can be used to test your application&apos;s service layer. Looking at the aforementioned architecture image, this will help us to replace/intercept &quot;Live HTTP&quot; clients with &quot;Stubbed HTTP&quot; clients. It&apos;s great when there are one or multiple <code>HttpClient</code> integrations in your application.</p><p>Most of the aforementioned packages will be used in the next examples.</p><h2 id="replacing-integrations-with-testdoubles">Replacing integrations with TestDoubles</h2><blockquote>By instantiating the full microservice in-memory using in-memory test doubles and datastores it is possible to write component tests that do not touch the network whatsoever. This can lead to faster test execution times and minimizes the number of moving parts reducing build complexity. However, it also means that the artifact being tested has to be altered for testing purposes to allow it to start up in a &apos;test&apos; mode. Dependency injection frameworks can help to achieve this by wiring the application differently based on configuration provided at start-up time.</blockquote><p>Not much more than the above quote needs to be said about our component tests. The tests run incredibly fast and give us a good idea of how the application will behave. I&apos;ve been building mostly backend APIs, and having the possibility to assert the outcome of an individual API regressively is a big plus for our development team. In the following paragraphs, we will put everything together. Per &quot;integration&quot;, I&apos;ll go over an example on how to replace the implementation to support a component test. Additionally, you will find the source code on the bottom of the post in the resources section.<br>We have examples for:</p><ul><li>Entity Framework</li><li>HttpClient</li></ul><p>While these are are only few and limited examples, these should be enough for your first main cases. But for other integrations, we generally found that they offer docker containers. This will be a subject for a later post.</p><h3 id="replacing-the-relational-database">Replacing the (relational) database</h3><p>Before going into too much detail, it is important to understand that there are a number of trade-offs when component testing your database/repository code. Below you will find a number of examples resembling the pros and cons from the documentation mentioned here: <a href="https://docs.microsoft.com/en-us/ef/core/testing/?ref=dotnetfromthemountain.com">Testing code that uses EF Core</a>. Essentially, depending on your type of TestDouble, there is a different level of integration with SQL/Entity Framework.</p><ul><li>InMemoryRepository: no integration with entity framework or SQL. Just a <br>self-made class with a list or dictionary</li><li>Entity Framework in-memory: No support for transactions or <u>raw</u> SQL</li><li>SQLite: Closest to database interaction, but not production worthy</li></ul><p>Depending on your scenario or component test, you can exchange these options and choose to adopt one or multiple solutions. In the example source code, you will find all three examples. </p><p><strong>InMemoryRepository (No integration)</strong><br>Assuming you have some sort of <code>IRepository</code> interface, we can use <a href="https://dotnetfromthemountain.com/aspnet-core-testing-strategies-the-basics/#repository-example">dependency injection to replace</a> from our previous post to provide an implementation with a version that uses a <code>List&lt;T&gt;</code> &#xA0;or a <code>Dictionary&lt;TKey,TValue&gt;</code>. There are a couple of advantages to this scenario. First, you don&apos;t have to worry about setting up the data. If you have a complex database, you might need to insert dependent data before you have it in the desired state for your test. Secondly, the &quot;ConfigureTestServices&quot; is relatively simple. </p><pre><code class="language-csharp">.ConfigureTestServices(services =&gt;
{
    services.AddSingleton(typeof(IRepository&lt;&gt;), typeof(InMemoryRepository&lt;&gt;));
});</code></pre><p>However, the big disadvantage is the component test never covers your <a href="https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping?ref=dotnetfromthemountain.com">Object-relational mapping (ORM) framework</a>. Ideally, it is much better to run against an actual database to test the integration as it is closer to the deployed scenario and can identify early integration mistakes. The challenge, in this case, is that it must also be able to run during your CI/CD pipelines. Furthermore, you need to make sure that if you run your component tests in parallel, that they don&apos;t conflict with one or another. Using an in-memory database may or may not be available to you depending on the ORM framework you use.</p><p><strong>Using entity framework in-memory (Low integration)</strong><br>In our case, EntityFramework does support this with <a href="https://www.nuget.org/packages/Microsoft.EntityFrameworkCore.InMemory/?ref=dotnetfromthemountain.com">Microsoft.EntityFrameworkCore.InMemory</a> NuGet package. The setup is simple but switching database providers requires some additional Dependency Injection tricks. When invoking the <code>services.AddDbContext&lt;MyDbContext&gt;()</code>, some additional steps are done by EF. It registers two services.</p><ul><li>A service to resolve <code>DbContext</code> </li><li>A service/factory method to resolve <code>DbContextOptions&lt;MyDbContext&gt;</code>. </li></ul><p>The preferred database provider is registered in these options. Thus, in order to switch the database provider from your default to the in-memory version, we need to override these options. Be aware that any other configuration you might have done, like enabling detailed errors, are also is overridden and needs to be reconfigured. Below is an example that uses the EntityFramework in-memory database.</p><pre><code class="language-csharp">webHostBuilder
    .ConfigureTestServices(services =&gt;
    {
        // Depending on the LifetimeScope of your options, it might either must be Scoped or Singleton. Default it&apos;s Scoped
        services.AddSingleton((serviceProvider) =&gt;
        {
            var optionsBuilder = new DbContextOptionsBuilder&lt;OrderDbContext&gt;().UseInMemoryDatabase(&quot;orders&quot;);
            return optionsBuilder.Options;
        });
    });</code></pre><p><strong>Using SQLite in-memory (Medium integration)</strong><br>For the <a href="https://docs.microsoft.com/en-us/ef/core/testing/sqlite?ref=dotnetfromthemountain.com">SQLite option</a>, we need to do a similar thing with our dependency injection. As you can see in the above example, configuring a different database provider is very easy, but for SQLite, we need to implement the <code>IDisposable</code> interface because we are working with external resources such as a database connection. To achieve this, you typically use a Setup/Teardown pattern. xUnit uses the UnitTest class constructor as &quot;Setup&quot;, and the <code>IDisposable.Dispose</code> will be the &quot;Teardown&quot;. </p><pre><code class="language-csharp">public class SqlLiteComponentTest : IDisposable
{
    private readonly DbConnection _connection;

    public SqlLiteComponentTest(ITestOutputHelper testOutputHelper)
    {
        // Ommitted
        _connection = CreateInMemoryDatabase();
    }

    private void CustomizeWebHostBuilder(IWebHostBuilder webHostBuilder)
    {
        webHostBuilder
            .ConfigureTestServices(services =&gt;
            {
                services.AddSingleton((serviceProvider) =&gt;
                {
                    var optionsBuilder = new DbContextOptionsBuilder&lt;OrderDbContext&gt;()
                        .UseSqlite(_connection);
                    return optionsBuilder.Options;
                });
            });
    }

    private static DbConnection CreateInMemoryDatabase()
    {
        var connection = new SqliteConnection(&quot;Filename=:memory:&quot;);
        connection.Open();
        return connection;
    }

    // Ommitted

    public void Dispose()
    {
        _connection.Dispose();
    }
}</code></pre><p>Again, it is important to note that depending on your scenario, you might choose one of the above options for your own component tests. Each choice has a different trade-off, as they work differently and provide a different level of integration to the database. But as shown here, getting started with these options are equally as simple, and they all work interchangeably. </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://dotnetfromthemountain.com/content/images/2021/10/image.png" class="kg-image" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests" loading="lazy" width="519" height="225"><figcaption>Showing three component tests with C# in-memory, EntityFramework in-memory or SQLite in-memory</figcaption></figure><h3 id="replacing-httpclients-with-a-mockhttphandler">Replacing HttpClients with a MockHttpHandler</h3><p>Another low level of dependency is your <code>HttpClient</code>. In our example application from the previous blog, we have created a service that integrates with Shopify. Now we can write a test that calls our order API, but that would fail because it tries to connect with the Shopify service. We need a way to work to intercept this, and we will be doing this with the MockHttp library.</p><p>Before writing a test, I generally use Postman to get an example requests and responses, and I store these inside a JSON file. With the help of these files, you can quickly set up a request in your code (specifying HttpMethod, QueryString and Headers) and returning a response the same way the API does. Below you&apos;ll see an example of such a setup.</p><pre><code class="language-csharp">MockHttpMessageHandler
    .When(HttpMethod.Get, &quot;https://shopify/api/v1/products/admin/api/2021-07/products/APPLE_IPHONE.json&quot;)
    .WithHeaders(new Dictionary&lt;string, string&gt;
    {
        [&quot;X-Shopify-Access-Token&quot;] = &quot;secret&quot;
    })
    .Respond(MediaTypeNames.Application.Json, File.ReadAllText(&quot;Shopify/Examples/APPLE_IPHONE.json&quot;));</code></pre><p>This is a convenient way of making component tests for your HTTP integrations. &#xA0;<br>Furthermore, in my personal experience, it has helped our team to even reproduce bugs. There were certain cases that we did not foresee, and through diagnosing and mimicking the request/response in a component test, we were able to quickly identify and resolve the bug, complementing our code base with another component test.</p><h2 id="the-component-test">The component test</h2><p>Bringing all this together we can create the following component test. This test first asserts that there are no orders, then it creates an order, and last but not least, it verifies that the order was created. This component test thus asserts that the HTTP integration works with Shopify. Additionally, it asserts our database is storing the order and we can retrieve it with all the correct details. </p><pre><code class="language-csharp">[Fact]
public async Task ComponentTest()
{
    // Arrange
    MockHttpMessageHandler
        .When(HttpMethod.Get, &quot;https://shopify/api/v1/products/admin/api/2021-07/products/APPLE_IPHONE.json&quot;)
        .WithHeaders(new Dictionary&lt;string, string&gt;
        {
            [&quot;X-Shopify-Access-Token&quot;] = &quot;secret&quot;
        })
        .Respond(MediaTypeNames.Application.Json, File.ReadAllText(&quot;Shopify/Examples/APPLE_IPHONE.json&quot;));

    // Act #1
    HttpResponseMessage getAllResponse = await SystemUnderTest.GetAsync(&quot;/api/v1/orders&quot;);
    var orders = await getAllResponse.Content.ReadFromJsonAsync&lt;Order[]&gt;();
    orders.Length.Should().Be(0);

    // Act #2
    HttpResponseMessage createResponse = await SystemUnderTest.PostAsync(
        &quot;/api/v1/orders&quot;, 
        JsonContent.Create(new CreateOrderDto()
        {
            ProductNumbers = new[] { &quot;APPLE_IPHONE&quot; },
            UserId = Guid.NewGuid(),
            TotalAmount = 495m,
        }));

    // Act #3
    getAllResponse = await SystemUnderTest.GetAsync(&quot;/api/v1/orders&quot;);


    // Assert
    createResponse.StatusCode.Should().Be(HttpStatusCode.OK);
    getAllResponse.StatusCode.Should().Be(HttpStatusCode.OK);
    orders = await getAllResponse.Content.ReadFromJsonAsync&lt;Order[]&gt;();
    orders.Length.Should().Be(1);
}</code></pre><h2 id="conclusion">Conclusion</h2><p>And that is we can create component tests. To summarize, we have done a couple of things. </p><ul><li>We have talked about component tests and what they are</li><li>We showed some NuGet packages that can help you with these component tests</li><li>Replaced an HTTP integration with examples</li><li>Replaced EntityFramework to run different in-memory modes</li><li>Brought all the above together into a single component test</li></ul><p>Writing component tests takes longer but the advantage is that you can create fine-grained tests that match some use cases or scenarios. This helped me and my co-workers to develop more reliable applications. In particular, &#xA0;for us, it became easier to reproduce bugs.</p><p>The scope of this post was to show you, how to create component tests. While they are great as a starting point to get a high &quot;code coverage&quot; and confidence in your application, there are still many more libraries that you can use to solve your functional or technical requirements. &#xA0;For example, look at Redis, RabbitMq, ElasticSearch, MongoDB, etc. However, these libraries are harder to replace with a <a href="https://martinfowler.com/bliki/TestDouble.html?ref=dotnetfromthemountain.com">TestDouble</a>. Instead, many of these libraries, when working in cloud-agnostic environments, provide a docker container implementation. In the next blog, I&apos;m going to show you how to spin up Docker Containers during your xUnit test so that we can use containers to provide an actual integration. These new kinds of tests then become integration tests. I would love to hear what your thoughts are. </p><blockquote><em>By combining unit, integration and component testing, we are able to achieve high coverage of the modules that make up a microservice and can be sure that the microservice correctly implements the required business logic. - Toby Clemson</em></blockquote><h3 id="next-post">Next post</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://dotnetfromthemountain.com/aspnet-core-testing-strategies-integration-test/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Different kind of testing strategies with ASP.NET Core: Using Docker to write Integration tests</div><div class="kg-bookmark-description">Greetings once again, dear readers. It&#x2019;s been quite some time since my last entry, and I&#x2019;m delighted to resume our discussion. In this ongoing series on ASP.NET Core testing strategies, today marks the unveiling of our third installment. In our previous post, we ventured into the world of component</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://dotnetfromthemountain.com/content/images/size/w256h256/2021/02/11779470811558095024-512.png" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"><span class="kg-bookmark-author">.NET from the mountain</span><span class="kg-bookmark-publisher">Rik van den Berg</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1583686298564-46fbffda0707?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=M3wxMTc3M3wwfDF8c2VhcmNofDV8fGNvbnRhaW5lcnN8ZW58MHx8fHwxNjk0NjE0MDg5fDA&amp;ixlib=rb-4.0.3&amp;q=80&amp;w=2000" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"></div></a></figure><h3 id="resources-credits">Resources / Credits</h3><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://m.do.co/c/da955a437503?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">DigitalOcean | Cloud Hosting for Builders</div><div class="kg-bookmark-description">Simple, scalable cloud computing solutions built for startups and small-to-midsize businesses.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://m.do.co/_next/static/media/apple-touch-icon.d7edaa01.png" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"><span class="kg-bookmark-author">Cloud Hosting for Builders</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.digitalocean.com/_next/static/media/social-share-default.e8530e9e.jpeg" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"></div></a><figcaption>Referral link to $200 free credits with digital ocean to try it out with 60 days</figcaption></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://martinfowler.com/articles/microservice-testing/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Testing Strategies in a Microservice Architecture</div><div class="kg-bookmark-description">The microservice architectural style presents challenges for organizing effective testing, this deck outlines the kinds of tests you need and how to mix them.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">martinfowler.com</span><span class="kg-bookmark-publisher">Toby Clemson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://martinfowler.com/articles/microservice-testing/meta-image.png" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/rikvandenberg/aspnetcore-component-tests/tree/part-2?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - rikvandenberg/aspnetcore-component-tests at part-2</div><div class="kg-bookmark-description">Contribute to rikvandenberg/aspnetcore-component-tests development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">rikvandenberg</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/bd66959b111e833e60562d339c0324780593aa2bbdd78d42fff2ec12b4d47a85/rikvandenberg/aspnetcore-component-tests" alt="Different kinds of testing strategies with ASP.NET Core:  Component tests"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Different kind of testing strategies with ASP.NET Core:  The basics]]></title><description><![CDATA[In this post we explain the different kind of tests we can make for ASP.NET Core applications, such as "component tests" and "integration test". This is the first post in a series of posts.]]></description><link>https://dotnetfromthemountain.com/aspnet-core-testing-strategies-the-basics/</link><guid isPermaLink="false">64137c8a4e2d8d152e469997</guid><category><![CDATA[.net]]></category><category><![CDATA[.net core]]></category><category><![CDATA[asp.net core]]></category><category><![CDATA[xUnit]]></category><category><![CDATA[testing]]></category><category><![CDATA[component test]]></category><category><![CDATA[integration test]]></category><category><![CDATA[microservices]]></category><dc:creator><![CDATA[Rik van den Berg]]></dc:creator><pubDate>Mon, 15 Mar 2021 21:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1589652717521-10c0d092dea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fGNvbXB1dGVyfGVufDB8fHx8MTYxNTg0MjU5NQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1589652717521-10c0d092dea9?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDZ8fGNvbXB1dGVyfGVufDB8fHx8MTYxNTg0MjU5NQ&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Different kind of testing strategies with ASP.NET Core:  The basics"><p>Most enterprises or development teams will have a quality gate in place, which dictates a percentage of code coverage. When writing new or changing your existing code, you also need to supplement them with unit tests. I enjoy writing unit tests when they have a more functional purpose. For example, creating orders containing products with discounts, testing a regression, or confirming the cause of a bug. Looking back at some of the tests I&apos;ve been writing myself with ASP.NET Core, there is more than meets the eye. These tests fit more in a different category of <a href="https://martinfowler.com/articles/practical-test-pyramid.html?ref=dotnetfromthemountain.com">the testing pyramid</a>. From top to bottom, we have:</p><ul><li>End-to-End tests</li><li>UI tests</li><li>Integration tests</li><li>Unit tests</li></ul><p>The higher we go in the pyramid, the more effort it takes to write these tests. During a &quot;rebuild&quot; project, we had a dedicated tester available. This rebuild project was to migrate some REST API&apos;s from ASP.NET 4.5 into ASP.NET Core. With containerization being a trend, we also decided to deploy and develop these API&apos;s using Docker. As we were optimizing our workflow, we also needed some initial end-to-end testing to be done. However, the work done by our tester was mostly manual (both for the legacy and the new applications).</p><p>While we were producing both ends of the spectrum as a team, we were still looking to increase our throughput for deliverables. When we started automating part of our test suite, we stumbled into the component/integration test area. But, our tester, who could write code, wasn&apos;t very well-known in the .NET core/Docker space. So we helped him with writing some code to self-host the app to send HTTP requests to the API.</p><p><strong>Our example application</strong><br>For these blog posts, I will use an example application to explain the ideas behind component testing. I build a small REST API application with dependencies to a SQL Database and an integration with an HTTP API. At the bottom of this blog, you will find the code in the resources.</p><p><strong>What&apos;s next?</strong><br>In the next couple of blog posts, I will describe how we can get started with ASP.NET Core and xUnit to create a component or an integration test. As a foundation for the other posts, this first blog post teaches you:</p><ul><li>The basics of self-hosting the ASP.NET Core application in xUnit </li><li>Using <code>WebApplictionFactory</code> and how to customize the startup</li><li>Change/configure settings for your test</li><li>How to replace dependencies such as an SQL database, RabbitMQ or HTTP clients </li><li>View everything logged by your application during a test</li></ul><p>With this introduction out of the way, let us get started.</p><p><strong><em>| Note</em></strong><em>: While each test in the pyramid has a different goal, xUnit doesn&apos;t classify or mark these tests differently. A test in xUnit is a method which means that a method can be a unit test, a component test, or an integration test.</em></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://images.unsplash.com/photo-1522542550221-31fd19575a2d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDV8fGRlc2lnbnxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core:  The basics" loading="lazy" width="5184" height="3456" srcset="https://images.unsplash.com/photo-1522542550221-31fd19575a2d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDV8fGRlc2lnbnxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=600 600w, https://images.unsplash.com/photo-1522542550221-31fd19575a2d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDV8fGRlc2lnbnxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1000 1000w, https://images.unsplash.com/photo-1522542550221-31fd19575a2d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDV8fGRlc2lnbnxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=1600 1600w, https://images.unsplash.com/photo-1522542550221-31fd19575a2d?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDV8fGRlc2lnbnxlbnwwfHx8&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2400 2400w" sizes="(min-width: 720px) 720px"><figcaption>Photo by <a href="https://unsplash.com/@halacious?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">HalGatewood.com</a> / <a href="https://unsplash.com/?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Unsplash</a></figcaption></figure><h3 id="sending-http-requests-to-your-asp-net-core-application-in-a-unit-test-">Sending HTTP requests to your ASP.NET Core application in a unit test.</h3><p>In our example application, we have a REST API. It is written with ASP.NET Core, and to start sending HTTP requests to this application, we need a way to host it. To achieve this, we need to carry out a couple of steps. ASP.NET Core was built with extension in mind and comes out of the box with self-hosting capabilities. In the <code>Microsoft.AspNetCore.Mvc.Testing</code> NuGet package, you will find a <code>WebApplicationFactory&lt;TEntryPoint&gt;</code> class (where <em>TEntryPoint</em> is either your <code>Startup</code> or <code>Program</code>). This class is capable of self-hosting the application anywhere in your code. Once this factory has started our API, we can then use this factory to resolve a <code>HttpClient</code>.</p><p>We can choose to create or inject our factory and resolve the <code>HttpClient</code>. This factory will do a couple of things for us. It establishes a <code>TestServer</code> that runs our self-hosted application. This server is responsible for hosting the application. It is similar to IIS, Kestrel or whatever your flavour might be. It configures the entire request pipeline and then starts processing requests. With the <code>HttpClient</code>, we then send out an HTTP request to an endpoint; in our case, this is <code>GET /api/v1/orders</code>, and we assert that the response is 200 OK.</p><pre><code class="language-csharp">public class OrderApiComponentTest
{
    private readonly WebApplicationFactory&lt;Program&gt; _webApplicationFactory;

    public OrderApiComponentTest()
    {
        _webApplicationFactory = new WebApplicationFactory&lt;Program&gt;();
    }

    [Fact]
    public async Task When_GET_is_called_on_the_api_should_return_200_OK()
    {
        // Arrange

        // Act
        HttpResponseMessage response = await SystemUnderTest.GetAsync(&quot;/api/v1/orders&quot;);

        // Assert
        response.StatusCode.Should().Be(HttpStatusCode.OK);
    }

    public HttpClient SystemUnderTest =&gt;
        _webApplicationFactory.CreateClient();
}</code></pre><p>With this as our foundation, we can start looking into more details. Depending on your application, this test might fail due to dependencies such as databases or other services not connecting. But we will try to resolve this along the way.</p><h3 id="webapplicationfactorytentrypoint-deep-dive">WebApplicationFactory&lt;TEntryPoint&gt; deep dive</h3><p><strong>Startup or Program</strong><br>The <code>WebApplicationFactory&lt;TEntryPoint&gt;</code> is used to create a <code>TestServer</code>. The <code>TEntryPoint</code> is a class that can either be the <code>Startup</code> or the <code>Program</code>. It doesn&apos;t really matter which one you use. The factory will use to entry point class use the assembly of the class to then try to discover one of the following static methods:</p><ul><li><code>IWebHost CreateWebHost(string[] args)</code></li><li><code>IWebHostBuilder CreateWebHostBuilder(string[] args)</code></li><li><code>IHostBuilder CreateHostBuilder(string[] args)</code></li></ul><p>When discovered, this method is then invoked and used to start and run the app. If it doesn&apos;t find this public static method, it will fail to startup.</p><p>Some NuGet packages or libraries that are available will tell you to customize this builder/host method. For them to hook into the ASP.NET Core runtime. For example, AutoFac is a library that changes the ServiceProvider. And we have written some libraries for our own projects that used custom initialization code in our Program <code>Main()</code> method to perform additional initialization tasks. &#xA0;</p><p>However, <strong><u>the factory doesn&apos;t invoke this </u></strong><code><strong><u>Main()</u></strong></code><strong><u> method</u></strong>. In the below (incorrect) example, the <code>Main()</code> method declares that AutoFac should be used as ServiceProvider. But because the factory only invokes the static method, AutoFac will not be configured for our test. So if you decide to add additional startup code to your main method, make sure it is invoked separately in your test. Or, you can create a custom class that inherits <code>WebApplicationFactory&lt;T&gt;</code> that does this for you.</p><pre><code class="language-csharp">public class Program
{
    // Any custom code here is not invoked by WebApplicationFactory.
    public static async Task Main(string[] args)
    {
        IHostBuilder hostBuilder = CreateHostBuilder(args);
        hostBuilder.UseServiceProviderFactory(new AutofacServiceProviderFactory())
        IHost host = hostBuilder.Build();
        await host.RunAsync();
    }

    // Discovered and invoked by the WebApplicationFactory
    public static IHostBuilder CreateHostBuilder(string[] args) =&gt;
        Host.CreateDefaultBuilder(args)            
            .ConfigureWebHostDefaults(webBuilder =&gt;
            {
                webBuilder.UseStartup&lt;Startup&gt;();
            });
}</code></pre><p><strong>Resolving services to arrange your data</strong><br>The <code>WebApplicationFactory</code> not only gives us the ability to host the application, but it also exposes the <code>IServiceProvider</code> of our application. This means we can resolve all of our services that have been registered inside our application. For example, if we need to pre-populate our database with some customers, we can resolve a repository to add some data.</p><p>If your classes are registered as singleton or transient, you can use the <code>Services</code> property on the factory. But if your classes are registered as scoped, you also need to resolve these services as scoped. We will populate our customers in the arrange step of our test. </p><pre><code class="language-csharp">// Arrange
IRepository&lt;Customer&gt; customers = 
    _webApplicationFactory.Services.GetRequiredService&lt;IRepository&lt;Customer&gt;&gt;();
customers.CreateAsync(new Customer(...));

// Arrange in scoped
using (IServiceScope scope = _webApplicationFactory.Services.CreateScope())
{
    IRepository&lt;Customer&gt; customers = scope.ServiceProvider.GetRequiredService&lt;IRepository&lt;Customer&gt;&gt;();
    customers.CreateAsync(new Customer(...));
}</code></pre><h3 id="adding-custom-appsetting-json">Adding custom appsetting.json</h3><p>Even Though we are self-hosting our application in a xUnit test, the application works the same as when you host in on IIS, cloud or Docker environment. One of the things ASP.NET Core automatically does is load a bunch of settings from different sources. But for your tests, you might need a way to override these. The runtime loads them in the following order: app settings, environment-specific settings, user secrets, system environment, and last but not least, the console arguments.</p><p>To override these settings, we can customize the factory to customize our web host. Our goal is to load additional app configurations specific to only our test. In the factory class, we have to call the <code>WithWebHostBuilder</code> method, which is a callback with the <code>IWebHostBuilder</code> as parameter.</p><pre><code class="language-csharp">public class OrderApiComponentTest
{
    private readonly WebApplicationFactory&lt;Program&gt; _webApplicationFactory;
    private readonly ITestOutputHelper _testOutputHelper;

    public OrderApiComponentTest(ITestOutputHelper testOutputHelper)
    {
        _webApplicationFactory = new WebApplicationFactory&lt;Program&gt;().WithWebHostBuilder(CustomizeWebHostBuilder);
        _testOutputHelper = testOutputHelper;
    }

    private void CustomizeWebHostBuilder(IWebHostBuilder webHostBuilder)
    {
        webHostBuilder
            .ConfigureAppConfiguration((context, configuration) =&gt;
            {
                string folder = Path.GetDirectoryName(GetType().Assembly.Location);
				string file = &quot;ComponentTest/component.test.json&quot;;
				configuration.AddJsonFile(Path.Combine(folder, file));
            });
    }
}</code></pre><p>To load the test-specific settings, you need to make sure you fully specify the path to your settings file. The application has a content root and a webroot. The content root is the one that is used to load assemblies, JSON/XML/DB files, and Razor views. But this content root is located in the project that you are self-hosting. In our case, that is the &quot;<strong>Api&quot; </strong>project. So when you only specify, for example, &quot;<em>ComponentTest/component.test.json</em>&quot;, it will not find the file because it is located in our &quot;<strong>Api.Test</strong>&quot; project.</p><figure class="kg-card kg-image-card"><img src="https://dotnetfromthemountain.com/content/images/2021/03/image-1.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core:  The basics" loading="lazy" width="460" height="204"></figure><p>So with the customizations in place for the web host, we can edit our JSON file to include settings. Additionally, we can write a test to assert the correct settings are loaded instead of our original values from the user secrets.</p><pre><code class="language-json">{
  &quot;Shopify&quot;: {
    &quot;ApiKey&quot;: &quot;COMPONENT_TEST&quot;
  }
}</code></pre><pre><code class="language-csharp">[Fact]
public async Task When_application_starts_up_should_load_config_from_json_file()
{
    // Arrange
    IConfiguration configuration = _webApplicationFactory.Services.GetRequiredService&lt;IConfiguration&gt;();

    // Act/Assert
    configuration[&quot;Shopify:ApiKey&quot;].Should().Be(&quot;COMPONENT_TEST&quot;);
}</code></pre><h3 id="changing-dependencies-by-using-test-specific-dependencies">Changing dependencies by using Test specific Dependencies</h3><p>If you use a relational database, a message queue or a NoSql database, we need to start thinking about how these dependencies will work if we self-host the application. During the development of your app or executing these tests locally on your own machine, they might have a chance of succeeding. But this might not be the case for everything. And if you have a continuous integration (CI) pipeline, running these tests on that build agent could also fail. The goal of these <u>component/integration tests</u> is that we are trying to make them so that they can also run inside a CI/CD environment. </p><p>So we need to replace some of our dependencies. Generally speaking, a <code>Startup</code> class will have a method called <code>ConfigureServices(IServiceCollection services)</code> where all our dependencies are registered. But during our tests, we might need to replace some services to pass the tests. For example a <code>IRepository</code>, <code>IBasicConsumer</code> or any other dependency with an abstraction. For now, we will be replacing these services with a <a href="https://martinfowler.com/bliki/TestDouble.html?ref=dotnetfromthemountain.com">TestDouble</a>. </p><p>To achieve this, we will call a special method <code>ConfigureTestServices</code> on the host builder. This is a special callback that is executed after your <code>Startup.ConfigureServices</code> and is only available when used in combination with the <code>WebApplicationFactory&lt;T&gt;</code>. This method allows you to override any previously registered services and replace them with something else, like a fake. Alternatively, this callback is also a place to configure test specific behaviour further. For example, configuring EntityFramework to use the SQLite implementation instead of a SQL server or, change how HTTP client/services are resolved. </p><!--kg-card-begin: html--><div id="repository-example"></div><!--kg-card-end: html--><pre><code class="language-csharp">private void CustomizeWebHostBuilder(IWebHostBuilder webHostBuilder)
{
    webHostBuilder
        .ConfigureTestServices(services =&gt;
        {
            services.AddScoped&lt;IRepository&lt;Customer&gt;, InMemoryRepository&lt;Customer&gt;&gt;()
            services.AddSingleton&lt;IBasicConsumer&gt;(new FakeBasicConsumer())
                    
            // Etc
        });
}</code></pre><h3 id="adding-output-using-logging-with-xunit">Adding output using logging with xUnit</h3><p>Last but not least, we are going to take a look at logging. Again ASP.NET Core automatically sets this part up for us. But in your company, you might be using an Application Performance Management (APM) tool such as <a href="https://www.datadoghq.com/product/apm/?ref=dotnetfromthemountain.com">DataDog</a> or <a href="https://docs.microsoft.com/en-us/azure/azure-monitor/app/app-insights-overview?ref=dotnetfromthemountain.com">Application Insights</a>. If you have configured these third party APM systems, your component or integration test will be sending logs to these tools. So we want to prevent that, but when debugging or investigating issues, it is still useful to have some form of logging. xUnit comes out of the box with a <code>ITestOutputHelper</code> class. Anything that is written to that class during your test is stored as an output with the test. </p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://dotnetfromthemountain.com/content/images/2021/03/image-5.png" class="kg-image" alt="Different kind of testing strategies with ASP.NET Core:  The basics" loading="lazy" width="1387" height="352" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2021/03/image-5.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2021/03/image-5.png 1000w, https://dotnetfromthemountain.com/content/images/2021/03/image-5.png 1387w" sizes="(min-width: 1200px) 1200px"></figure><p>Together with the NuGet package, <code>Xunit.Extensions.Logging</code> we can register this class as an implementation of <code>ILogger</code>. First, we have to remove all of the other log providers to send anything to your APM. And then, we will add the xUnit <code>ITestOutputHelper</code> class. Any logs will then be written as output and be available in the test explorer, as shown in the above picture. This must also be done to customize our web host builder by using the <code>ConfigureLogging()</code> method. First, we accept <code>ITestOutputHelper</code> as a constructor parameter of the test class. And then, we register the xUnit class with our logging builder.</p><pre><code class="language-csharp">// Accept ITestOutputHelper as constructor parameter.
public OrderApiComponentTest(ITestOutputHelper testOutputHelper)
{
    _webApplicationFactory = new WebApplicationFactory&lt;Program&gt;().WithWebHostBuilder(CustomizeWebHostBuilder);
    _testOutputHelper = testOutputHelper;
}

private void CustomizeWebHostBuilder(IWebHostBuilder webHostBuilder)
{
    webHostBuilder
        .ConfigureLogging(loggingBuilder =&gt;
        {
            loggingBuilder.ClearProviders();
            loggingBuilder.AddXunit(_testOutputHelper);
        });
}</code></pre><h3 id="conclusion">Conclusion</h3><p>With this post as our foundation, we will continue to explore writing component and integration tests for ASP.NET Core. You might have already seen some hints of what a &quot;component test&quot; can look like. This post has shown you some of the basics that we will be using when testing an ASP.NET Core application in a xUnit test. We have gone through:</p><ul><li>Self-hosting our web application in a test using xUnit</li><li>Customizing the application with <code>WebApplicationFactory</code></li><li>Adding test specific settings</li><li>Replacing dependencies specific to the test</li><li>Replacing existing logging with the xUnit output for additional debugging purposes</li></ul><p>We will go deeper into how we can write our component and integration tests in the next posts.</p><h3 id="next-post">Next post</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://dotnetfromthemountain.com/aspnet-core-testing-strategies-component-test/"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Different kinds of testing strategies with ASP.NET Core: Component tests</div><div class="kg-bookmark-description">Writing component tests takes longer but the advantage is that you can create fine-grained tests that match some use cases or scenarios</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://dotnetfromthemountain.com/favicon.png" alt="Different kind of testing strategies with ASP.NET Core:  The basics"><span class="kg-bookmark-author">.NET from the mountain</span><span class="kg-bookmark-publisher">Rik van den Berg</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.unsplash.com/photo-1532188363366-3a1b2ac4a338?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MnwxMTc3M3wwfDF8c2VhcmNofDJ8fGNvbXBvbmVudCUyMGxhcHRvcHxlbnwwfHx8fDE2MjY0MzkxMTM&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Different kind of testing strategies with ASP.NET Core:  The basics"></div></a></figure><h3 id="resources">Resources</h3><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://m.do.co/c/da955a437503?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">DigitalOcean | Cloud Hosting for Builders</div><div class="kg-bookmark-description">Simple, scalable cloud computing solutions built for startups and small-to-midsize businesses.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://m.do.co/_next/static/media/apple-touch-icon.d7edaa01.png" alt="Different kind of testing strategies with ASP.NET Core:  The basics"><span class="kg-bookmark-author">Cloud Hosting for Builders</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://www.digitalocean.com/_next/static/media/social-share-default.e8530e9e.jpeg" alt="Different kind of testing strategies with ASP.NET Core:  The basics"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://martinfowler.com/articles/microservice-testing/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Testing Strategies in a Microservice Architecture</div><div class="kg-bookmark-description">The microservice architectural style presents challenges for organizing effective testing, this deck outlines the kinds of tests you need and how to mix them.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">martinfowler.com</span><span class="kg-bookmark-publisher">Toby Clemson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://martinfowler.com/articles/microservice-testing/meta-image.png" alt="Different kind of testing strategies with ASP.NET Core:  The basics"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-5.0&amp;ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Integration tests in ASP.NET Core</div><div class="kg-bookmark-description">Learn how integration tests ensure that an app&#x2019;s components function correctly at the infrastructure level, including the database, file system, and network.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Microsoft Docs</span><span class="kg-bookmark-publisher">Rick-Anderson</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://docs.microsoft.com/en-us/media/logos/logo-ms-social.png" alt="Different kind of testing strategies with ASP.NET Core:  The basics"></div></a></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/rikvandenberg/aspnetcore-component-tests/tree/part-1?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - rikvandenberg/aspnetcore-component-tests at part-1</div><div class="kg-bookmark-description">Contribute to rikvandenberg/aspnetcore-component-tests development by creating an account on GitHub.</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.com/fluidicon.png" alt="Different kind of testing strategies with ASP.NET Core:  The basics"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">rikvandenberg</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/bd66959b111e833e60562d339c0324780593aa2bbdd78d42fff2ec12b4d47a85/rikvandenberg/aspnetcore-component-tests" alt="Different kind of testing strategies with ASP.NET Core:  The basics"></div></a></figure>]]></content:encoded></item><item><title><![CDATA[Starting a Ghost blog for the cost of $5 per month]]></title><description><![CDATA[What is this website? Which CMS are you using and and how are am I hosting it. Please read this post to answer all these questions. We are using Ghost as CMS, DigitalOcean for our hosting and some other neat little tools]]></description><link>https://dotnetfromthemountain.com/starting-a-ghost-blog-for-the-cost-of-5-dollars-per-month/</link><guid isPermaLink="false">64137c8a4e2d8d152e469994</guid><category><![CDATA[Ghost]]></category><category><![CDATA[Meta]]></category><category><![CDATA[LetsEncrypt]]></category><category><![CDATA[JAMStack]]></category><category><![CDATA[Blog]]></category><dc:creator><![CDATA[Rik van den Berg]]></dc:creator><pubDate>Sat, 13 Feb 2021 23:00:00 GMT</pubDate><media:content url="https://images.unsplash.com/photo-1584907797015-7554cd315667?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDR8fHN0YXJ0fGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" medium="image"/><content:encoded><![CDATA[<img src="https://images.unsplash.com/photo-1584907797015-7554cd315667?crop=entropy&amp;cs=tinysrgb&amp;fit=max&amp;fm=jpg&amp;ixid=MXwxMTc3M3wwfDF8c2VhcmNofDR8fHN0YXJ0fGVufDB8fHw&amp;ixlib=rb-1.2.1&amp;q=80&amp;w=2000" alt="Starting a Ghost blog for the cost of $5 per month"><p>It feels great to have a professional (and personal) blog space. I enjoy writing about technical stuff and my experiences. And over the past years, I&apos;ve attempted many times to launch a blog, but most of these attempts failed. The idea of hosting, deploying and managing everything was very looming and off-putting. I often find myself <a href="https://www.urbandictionary.com/define.php?term=Down+the+Rabbit+Hole&amp;ref=dotnetfromthemountain.com">falling into a rabbit hole</a> trying to solve these things through automation. Creating a fully automated CI/CD pipeline to satisfy all of my wishes. But then, in the end, I always gave up because the direction or result just wasn&apos;t there. </p><p><em><strong>| Note:</strong> No later than a couple of weeks, Ghost has release version </em><a href="https://ghost.org/changelog/4/?ref=dotnetfromthemountain.com"><em>Ghost 4.0</em></a><em> and offers a subscription starting at $9 (yearly). However, if you are a little more technical and want access to more features and customizations, I would recommend continuing to read the post below. </em></p><p>I finally found a setup easy enough to start with, and I&apos;m delighted. Looking back, I could have made things easier for myself. I&apos;m probably not going to use all of the things that are now at my disposal. But funny enough, it&apos;s always nice to have additional tools&#x1F609; Let us go through the list of technical things I&apos;ve chosen, starting with Ghost.</p><hr><h3 id="the-spooky-blog">The spooky blog</h3><p>So as my blog, I choose <a href="https://ghost.org/?ref=dotnetfromthemountain.com">Ghost</a>. It is not really a blog but more of a publishing platform. Over the past couple of months, I&apos;ve always been drawn back to the list of features offered by them. For publishing, it offers an overall complete experience. It uses Markdown, which makes writing posts with code very friendly. Tagging featured posts and SEO makes my content more (hopefully) findable and organized. Anything that is a basic necessity for a blog. </p><p>You can style your website by choosing a theme available through different marketplaces. Both free or paid themes are available, or you can even make your own. It was one of the experiments, and it was fun and great to learn more about Ghost. It also led me to explore JAMStack and Gatsby.JS. But enough about that rabbit hole.</p><p>Last but not least, Ghost has a more noteworthy feature which is its members and subscriptions. Your readers can register for free, and allows them to receive notifications/newsletters when you publish them. But they can also subscribe for a monthly or yearly fee. Respectively allowing you to publish content accessible to registered users only or paying users. Some more thoughts of why I ended with Ghost:</p><ul><li><em>Audience:</em> interaction with the readers through many means such as sharing, comments and newsletters. </li><li><em>Newsletters:</em> You will have to connect a mailing service such as MailGun to start sending emails, but I really like the idea of having the option to start sending newsletters about maybe the smaller things that I run into and are not worth a post. Additionally, Ghost allows you to segment your emails, giving you the option to send them to free members or paid members (or both). </li><li><em>Business:</em> As this is a professional blog, any future business opportunities or career paths that open up are great bonuses.</li><li><em>Integrations:</em> Comments, analytics, workflows. The possibilities are great, although I don&apos;t see myself using anything special. <a href="https://ghost.org/integrations/?ref=dotnetfromthemountain.com">Here is a list of all the integrations currently possible</a>. </li></ul><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ghost.org/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">Ghost: Turn your audience into a business</div><div class="kg-bookmark-description">The world&#x2019;s most popular modern publishing platform for creating a new media platform. Used by Apple, SkyNews, Buffer, OpenAI, and thousands more.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Ghost - The Professional Publishing Platform</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ghost.org/images/meta/ghost.png" alt="Starting a Ghost blog for the cost of $5 per month"></div></a></figure><h3 id="choosing-the-right-vessel-for-the-sea-of-internet">Choosing the right vessel for the sea of internet</h3><p>While exploring Ghost as a blog, I also looked into the hosting options. Ghost is a non-profit organization, and to support that organization, they offer a hosting service called <a href="https://ghost.org/pricing/?ref=dotnetfromthemountain.com">Ghost(Pro)</a>. This service costs $36 or $29 per month, depending on your prepay for the year. This price is unattractive for just trying to start a blog. </p><p>But Ghost also documents some alternatives. Whether it is self-hosted or containerized with Docker. Working with containers has taught me to appreciate enough simplicity of creating a container and deploying it in different clouds, such as AWS or Azure. But these experiments again left me with a sour aftertaste. The overhead of creating a container, managing the database and testing each consecutive change put me off and stopped me in my tracks to further progress. So what I really wanted was a single click deployment without worrying too much about backup, configuration, and such. </p><p>Luckily Ghost has an official partner <strong><a href="https://www.digitalocean.com/?ref=dotnetfromthemountain.com">DigitalOcean</a></strong>, and they provide prebuilt packages. Even better, they provide a &quot;Ghost 1-Click App&quot; on their <a href="https://marketplace.digitalocean.com/apps/ghost?ref=dotnetfromthemountain.com">marketplace</a> and promise to have an instance up and running in 2 minutes. They offer a couple of sizes for virtual machine sizes, and the cheapest one with decent performance comes for $5 per month. This is a great starting price, and for the first 2 months, there is a free $100 credit. </p><figure class="kg-card kg-image-card"><img src="https://dotnetfromthemountain.com/content/images/2021/02/image-5.png" class="kg-image" alt="Starting a Ghost blog for the cost of $5 per month" loading="lazy" width="1548" height="641" srcset="https://dotnetfromthemountain.com/content/images/size/w600/2021/02/image-5.png 600w, https://dotnetfromthemountain.com/content/images/size/w1000/2021/02/image-5.png 1000w, https://dotnetfromthemountain.com/content/images/2021/02/image-5.png 1548w" sizes="(min-width: 720px) 720px"></figure><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://ghost.org/docs/install/digitalocean/?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">How to install Ghost on Digital Ocean - Official guide</div><div class="kg-bookmark-description">A full production install guide for how to install the Ghost professional publishing platform on a production server running Ubuntu 16.04, 18.04 or 20.04.</div><div class="kg-bookmark-metadata"><span class="kg-bookmark-author">Ghost - The Professional Publishing Platform</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://ghost.org/images/meta/Ghost-Docs.jpg" alt="Starting a Ghost blog for the cost of $5 per month"></div></a></figure><p>All that is required from you is that you bring your own domain. If you don&apos;t have one at the moment, that is fine. You can come back after creating the VM. The installation guide was easy enough, and after following every step, I had my blog running, as promised, in a couple of minutes. Since I didn&apos;t have a domain yet, I was playing around a bit with ghost using the IP address of the VM. </p><p>After purchasing my domain, I followed <a href="https://www.digitalocean.com/community/tutorials/how-to-point-to-digitalocean-nameservers-from-common-domain-registrars?ref=dotnetfromthemountain.com">this handy guide</a> on how to connect my domain to the Virtual Machine. After that, I <em>impatiently</em> waited for things to propagate, and presto, everything was working as expected. With the domain connected, it was time to go back to the VM and set up the SSL.</p><ol><li>Connect to the VM using an SSH session</li><li>Login as ghost-mgr &#xA0;<code>sudo -i -u ghost-mgr</code></li><li>Navigate to the ghost folder location. Typically at <code>/var/www/ghost/</code> </li><li>Run <code>ghost setup ssl</code> and follow the instructions</li></ol><p>And that was it&#x2014;time for the launch. Let the countdown begin. 10...9...8...</p><h3 id="we-have-liftoff-">We have liftoff &#x1F680;</h3><p>That pretty much concludes the setup. I also created a personal website as well with the same setup. It was easy enough to do it again. This personal website focuses more on personal and travel-related topics. If you want to take a look <a href="https://rikvandenberg.com/?ref=dotnetfromthemountain.com">https://rikvandenberg.com </a></p><p>To conclude my initial journey:</p><ul><li>Launched a Ghost website</li><li>I&apos;m hosting it on a $5 VM on DigitalOcean</li><li>Bought a domain</li><li>Setup an SSL with the LetsEncrypt integration of Ghost</li></ul><p>Feel free to ask any questions or leave a comment. I would love to hear your feedback or interact with you as a reader. </p><p>If you are interested in trying this all for yourself or want to try DigitalOcean and <a href="https://www.digitalocean.com/products/?ref=dotnetfromthemountain.com">see what they&apos;ve got to offer</a>, you will find an <u>affiliate link</u> below. When you sign up, you will receive $100 of credit for a period of 60 days. After that, if you decide to continue using DigitalOcean, I also receive additional credit.</p><figure class="kg-card kg-bookmark-card kg-card-hascaption"><a class="kg-bookmark-container" href="https://m.do.co/c/da955a437503?ref=dotnetfromthemountain.com"><div class="kg-bookmark-content"><div class="kg-bookmark-title">DigitalOcean &#x2013; The developer cloud</div><div class="kg-bookmark-description">Helping millions of developers easily build, test, manage, and scale applications of any size &#x2013; faster than ever before.</div><div class="kg-bookmark-metadata"></div></div><div class="kg-bookmark-thumbnail"><img src="https://images.prismic.io/www-static/0026a57b93abe5b04413765253903472dab58e11_general-droplets_blog-v4_twitter---facebook.png?auto=compress,format" alt="Starting a Ghost blog for the cost of $5 per month"></div></a><figcaption><u>Affiliate link</u> to try DigitalOcean with $100 credit for 60 days which benefits me as well</figcaption></figure><h3></h3>]]></content:encoded></item></channel></rss>