<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB"><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://www.forkinthecode.net/atom.xml" rel="self" type="application/atom+xml" /><link href="https://www.forkinthecode.net/" rel="alternate" type="text/html" hreflang="en-GB" /><updated>2025-12-31T17:21:02+00:00</updated><id>https://www.forkinthecode.net/atom.xml</id><title type="html">a fork in the code</title><subtitle>Andrew Poole&apos;s random thoughts mostly about software engineering</subtitle><author><name>Andrew Poole</name></author><entry><title type="html">Introducing the Azure Service Bus Emulator UI</title><link href="https://www.forkinthecode.net/2025/12/19/azure-service-bus-emulator-ui-for-aspire.html" rel="alternate" type="text/html" title="Introducing the Azure Service Bus Emulator UI" /><published>2025-12-19T00:00:00+00:00</published><updated>2025-12-19T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2025/12/19/azure-service-bus-emulator-ui-for-aspire</id><content type="html" xml:base="https://www.forkinthecode.net/2025/12/19/azure-service-bus-emulator-ui-for-aspire.html"><![CDATA[<p>TL/DR - If you’re using the Azure Service Bus emulator with .NET Aspire and missing the ability to peek at messages or send test messages like you can in the Azure Portal or ServiceBusExplorer, I’ve built a tool for you! The <strong>Aspire ASB Emulator UI</strong> is a Blazor-based web UI that plugs right into your Aspire AppHost.</p>

<h2 id="the-problem">The Problem</h2>

<p>.NET Aspire makes it incredibly easy to spin up local resources, including the <a href="https://learn.microsoft.com/azure/service-bus-messaging/test-locally-with-service-bus-emulator">Azure Service Bus Emulator</a>. This is fantastic for local development as it allows us to test against a real(ish) service bus without needing an internet connection or costing a penny.</p>

<p>However, one thing I really missed from the “real” Azure Service Bus experience was a UI to visualise what’s going on, typically the Azure Portal or one of the various standalone apps. Being able to jump into a queue, see how many messages are sitting there, peek at the dead-letter queue, or manually send a test message to trigger a workflow is invaluable. However these tools use the ASB Admin interface, which the emulator explicitly doesn’t support.</p>

<p>With the emulator running in a container, you’re often left flying blind or writing throwaway console apps just to push a message onto a queue.</p>

<p>Luckily through the magic of Aspire we can connect to the backend SQL database and rummage around for a table which exposes the configured entities. I wasn’t able to accurately query message counts for all entity types via the database, but once we have the list of entities to parse, we can cheat and use the ordinary client to peek and get message counts that way.</p>

<h2 id="the-solution-aspire-asb-emulator-ui">The Solution: Aspire ASB Emulator UI</h2>

<p>I decided to build a tool to fill this gap. <strong>Aspire ASB Emulator UI</strong> is basically Postman for the ASB emulator!</p>

<p>It’s a Blazor Interactive Server application that you can wire up directly in your Aspire AppHost. It connects to your emulator instance and gives you a nice UI to explore and interact with your entities.</p>

<p><img src="/images//AsbEmulatorUiScreenshot.gif" alt="Aspire ASB Emulator UI Screenshot" /></p>

<h3 id="key-features">Key Features</h3>

<p>Here is what you can do with it right now:</p>

<ul>
  <li>Entity Explorer**: View all your queues and topics. See real-time message counts for both active and dead-letter queues.</li>
  <li>Message Sender**: A full-featured message sender with a Monaco Editor (VS Code style). You can set broker properties like <code class="language-plaintext highlighter-rouge">MessageId</code>, <code class="language-plaintext highlighter-rouge">CorrelationId</code>, and <code class="language-plaintext highlighter-rouge">ScheduledEnqueueTime</code>.</li>
  <li>Message Viewer**: Peek or receive messages from your queues to see what’s actually going on inside them.</li>
  <li>Canned Messages**: Save frequently used test messages and even use AI to generate templates.</li>
  <li>Placeholder Syntax**: Use dynamic values in your test messages like <code class="language-plaintext highlighter-rouge">~newGuid~</code> or <code class="language-plaintext highlighter-rouge">~now+5m~</code> so you don’t have to manually edit JSON every time you send a test.</li>
</ul>

<h2 id="getting-started">Getting Started</h2>

<p>Getting it running is super simple. It’s designed to feel just like adding any other resource in Aspire.</p>

<p>First, add the hosting package to your <strong>AppHost</strong> project:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet add package AspireAsbEmulatorUi.Hosting
</code></pre></div></div>

<p>Then, in your <code class="language-plaintext highlighter-rouge">Program.cs</code>, just wire it up to your Service Bus resource:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="n">DistributedApplication</span><span class="p">.</span><span class="nf">CreateBuilder</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>

<span class="c1">// Add Azure Service Bus and configure it to run with the emulator</span>
<span class="kt">var</span> <span class="n">serviceBus</span> <span class="p">=</span> <span class="n">builder</span>
    <span class="p">.</span><span class="nf">AddAzureServiceBus</span><span class="p">(</span><span class="s">"myservicebus"</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">RunAsEmulator</span><span class="p">(</span><span class="n">c</span> <span class="p">=&gt;</span> <span class="n">c</span><span class="p">.</span><span class="nf">WithLifetime</span><span class="p">(</span><span class="n">ContainerLifetime</span><span class="p">.</span><span class="n">Persistent</span><span class="p">));</span>

<span class="c1">// Add the ASB Emulator UI</span>
<span class="n">builder</span><span class="p">.</span><span class="nf">AddAsbEmulatorUi</span><span class="p">(</span><span class="s">"asb-ui"</span><span class="p">,</span> <span class="n">serviceBus</span><span class="p">);</span>

<span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">().</span><span class="nf">Run</span><span class="p">();</span>
</code></pre></div></div>

<p>That’s it! When you run your Aspire project, you’ll see a new resource called “asb-ui” in the dashboard. Click the endpoint, and you’re in.</p>

<h2 id="why-i-built-it">Why I Built It</h2>

<p>I’m a big fan of great developer experience. Friction in local testing—like having to manually craft a JSON payload and run a script just to test a message handler—adds up over time. Tools like this help keep the flow going. It’s very easy to create small tools like this and integrate them with an Aspire orchestration and also to share them. Conversely it is often <em>not</em> very easy to deploy even simple tools like this into a real enterprise environment.</p>

<p>Plus, it was a great excuse to play with <strong>Blazor Interactive Server</strong> and <strong>Tailwind CSS</strong> in a .NET 10 context!</p>

<h3 id="one-interesting-aspire-related-rabbit-hole">One interesting Aspire related rabbit hole…</h3>

<p>When building the hosting extension, one challenge I faced was getting the SQL password for the emulator’s backend database. The emulator resource has an environment variable <code class="language-plaintext highlighter-rouge">MSSQL_SA_PASSWORD</code>, but in Aspire, these values are often expressions or references that get evaluated at runtime. To get the actual value during the resource wiring phase, you can’t just read the environment variable dictionary directly. Instead, you have to use <code class="language-plaintext highlighter-rouge">ProcessEnvironmentVariableValuesAsync</code> to resolve the final value.</p>

<p>Here is how I grabbed the password from the emulator resource to pass it to the UI:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Process container environment variables to extract the SQL password</span>
<span class="k">await</span> <span class="n">sbResource</span><span class="p">.</span><span class="nf">ProcessEnvironmentVariableValuesAsync</span><span class="p">(</span>
    <span class="n">context</span><span class="p">.</span><span class="n">ExecutionContext</span><span class="p">,</span>
    <span class="k">async</span> <span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">unprocessedValue</span><span class="p">,</span> <span class="n">processedValue</span><span class="p">,</span> <span class="n">exception</span><span class="p">)</span> <span class="p">=&gt;</span>
    <span class="p">{</span>
        <span class="c1">// Capture SQL password</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">key</span> <span class="p">==</span> <span class="s">"MSSQL_SA_PASSWORD"</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="c1">// processedValue contains the actual resolved password!</span>
            <span class="n">context</span><span class="p">.</span><span class="n">EnvironmentVariables</span><span class="p">[</span><span class="s">"asb-sql-password"</span><span class="p">]</span> <span class="p">=</span> <span class="n">processedValue</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">},</span>
    <span class="n">context</span><span class="p">.</span><span class="n">Logger</span><span class="p">,</span>
    <span class="n">CancellationToken</span><span class="p">.</span><span class="n">None</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="check-it-out">Check It Out</h2>

<p>The project is open source and available on GitHub. I’d love for you to give it a try and let me know what you think.</p>

<p><a href="https://github.com/andrewjpoole/aspire-asb-emulator-ui">View on GitHub</a></p>

<p>Happy coding! 🚀</p>]]></content><author><name>Andrew Poole</name></author><category term="azure service bus ui" /><category term="asb UI" /><category term="asb gui" /><category term="aspire" /><category term="azure-service-bus" /><category term="tools" /><summary type="html"><![CDATA[TL/DR - If you’re using the Azure Service Bus emulator with .NET Aspire and missing the ability to peek at messages or send test messages like you can in the Azure Portal or ServiceBusExplorer, I’ve built a tool for you! The Aspire ASB Emulator UI is a Blazor-based web UI that plugs right into your Aspire AppHost.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images//asb-emulator-ui-title.png" /><media:content medium="image" url="https://www.forkinthecode.net/images//asb-emulator-ui-title.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Assert against trace data for integration tests with .Net Aspire and the QueryableTraceCollector</title><link href="https://www.forkinthecode.net/2025/05/31/assert-against-trace-data-for-integration-tests-with-aspire-and-the-queryabletracecollector.html" rel="alternate" type="text/html" title="Assert against trace data for integration tests with .Net Aspire and the QueryableTraceCollector" /><published>2025-05-31T00:00:00+00:00</published><updated>2025-05-31T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2025/05/31/assert-against-trace-data-for-integration-tests-with-aspire-and-the-queryabletracecollector</id><content type="html" xml:base="https://www.forkinthecode.net/2025/05/31/assert-against-trace-data-for-integration-tests-with-aspire-and-the-queryabletracecollector.html"><![CDATA[<h1 id="integration-tests-how-not-to-hate-them-️">Integration Tests: How Not to Hate Them ❤️</h1>

<h3 id="tldr">TL/DR;</h3>

<p>Recently while preparing for a talk on integration tests, I tried a few things and discovered something I think is potentially game changing; asserting against open telemetry trace data for integration tests! This makes the tests less complex and less brittle, easier to run locally and will probably make your systems easier to support by temping you to add better telemetry earlier on in the dev loop! Basically a win-win-win-win…🧐</p>

<h2 id="background">Background</h2>

<p>I have always disliked integration tests because they expose just how hard it can be to run a modern distributed app locally, especially in a team scenario where people have differing preferences of tooling/setup/even OS! So we often give up on running integration tests locally altogether and end up relying on the integration tests passing in an environment… after a release… after a CI build… after we have checked in our change and hoped for the best! This is not an ideal feedback loop and could easily take 30mins+ 🥱</p>

<p>The other thing which annoys me about integration tests is having to assert in several ways against various different things to ensure the expected behaviour happened, E.g. using database connections to query or asb queues for assertions. Its possible of course, but think of the case of a message broker like Azure Service Bus, we need to peek at a queue to ensure first no old messages exist, then again at the right moment to assert that the expected message has appeared, then after the correct amount of time has passed we check again to see that the message has dissapeared, but we also need to check that it didn’t appear in the dead letter queue! Even after that we still aren’t certain that it was processed unless we check some other outcome like a domain event was persisted or other db update occured etc. The dance of timing here certainly plays a part in these kinds of tests being notoriously brittle. There must be a better way…</p>

<p>Clearly the effort required to get integration tests running locally is worthwhile and my talk set out to make that case and provide a few tips.</p>

<h2 id="enter-net-aspire-for-exceptional-local-development-experience">Enter .Net Aspire for Exceptional Local Development Experience!</h2>

<p><a href="https://github.com/dotnet/aspire">.NET Aspire</a> has been developed to solve the exact problem of running distributed apps locally and it was on my list to try anyway. Aspire allows us to define our services in terms of executable apps, services, configuration and the relationships between them all. This is also done in one single file - amazing! There are lots of excellent resources on what Aspire is and how to use it to orchestrate a distributed app, from here I will concentrate specifically how it can help with integration tests.</p>

<h2 id="open-telemetry">Open telemetry</h2>

<p>Aspire also wires up all of the resources to send <a href="https://opentelemetry.io/">Open Telemetry</a> data to the dashboard where it can be viewed and filtered while the app is running locally. The value of this can not be understated. Once we start using this data to see whats happening and inspect what’s gone before, it becomes addictive, we start having realisations like “if we could add that piece of data to this trace, then we’d save x minutes looking it up from 3 db queries during an incident if scenario y ever happens”. To have <em>this</em> kind of view of an app, at <em>this</em> early a stage in the development loop is amazing! See below for code to add custom trace data to a process or to bridge a process gap.</p>

<p><img src="/images//open-telemetry-trace-data-aspire-dashboard.png" alt="trace data in Aspire dashboard" /></p>

<h2 id="aspire-tests">Aspire Tests</h2>

<p>Aspire also supports testing a distributed app using the same orchestration code, meaning that when an Aspire test is run, the same dependencies get started, the same service discovery and configuration happens and we get the opportunity to create clients to our services and call APIs or send messages etc. These tests take quite a while to run due to the nature of whats actually being spun up, but they are much faster than waiting for the check-in -&gt; CI build -&gt; release to env -&gt; run tests loop. Official docs <a href="https://learn.microsoft.com/en-us/dotnet/aspire/testing/overview">here</a>.</p>

<h2 id="a-eureka-moment">A Eureka moment!💡</h2>

<p>So at this moment, while experimenting with Aspire tests, it dawned on me that all that lovely trace data would be absolutely perfect for asserting that expected behaviour ocurred as expected, its a forensic single-source-of-truth timeline of everything that happened since the app started! In other words the perfect thing to assert against!😃</p>

<p>Alas I also realised a few things:</p>

<p>There are some differences between Aspire tests the Aspire localdev ‘F5’ experience, one being that the dashboard doesn’t run during tests. The dashboard is the component that collects open telemetry data, all other orchestrated services are configured to send their telemetry data to the dashboard via gRPC. If the dashboard doesn’t run during tests, then nothing is listening to collect the trace data.☹️</p>

<p>Now it is possible to configure that dashboard to run during tests, but there are no public endpoints available with which to query the data. Again it is possible to use reflection to get access to the private view model, but I was unable to get that to work.😕</p>

<h2 id="asserting-against-trace-data">Asserting against trace data!🚀</h2>

<p>So, thinking through the requirements:</p>
<ul>
  <li>We need something that all of the resources can send data to, and given each resource runs in its own process, that likely means a new resource</li>
  <li>Various official OTEL backends exist, but they all seemed to be quite heavywieght for this use-case</li>
  <li>We need an easy way to assert against the collected trace data</li>
  <li>Ideally we should be able to filter just the interesting trace data, otherwise its a firehose!</li>
  <li>We need to be able to clear collected trace data between tests</li>
  <li>Ideally it should be simple to setup and in-keeping with Aspire and Aspire tests</li>
</ul>

<p>So, after some experiementation, the simplest solution I could come up with is:</p>
<ul>
  <li>A simple minimal API with some methods and an in-memory collection</li>
  <li>An implementation of <code class="language-plaintext highlighter-rouge">OpenTelemetry.BaseExporter&lt;Activity&gt;</code> which will send filtered trace data to the API, packaged up as an Aspire Client package</li>
  <li>A lite version of Activity to serialise and pass around</li>
  <li>A container image of the API in DockerHub</li>
  <li>An Aspire integration package to easily add the API as a container resource</li>
</ul>

<h2 id="filling-in-some-trace-data-gaps">Filling in some trace data gaps⛳</h2>

<p>I noticed that in a couple of places I was missing vital info about what had happened, I was looking at this from a ‘what would be ideal to assert against’ point of view, but ‘what would be helpful when investigating an incident’ is another equally valid and useful one.</p>

<h3 id="notificationservice">NotificationService</h3>

<p>In my dummy Notification Service, I did not have any trace data showing me when the notification is ‘made’, because being a dummy app, it was not doing anything which is automatically traced (i.e. making an API call, sending a message or calling the database), so I added the following code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">activity</span> <span class="p">=</span> <span class="n">Activity</span><span class="p">.</span><span class="nf">StartActivity</span><span class="p">(</span><span class="s">"User Notification Sent"</span><span class="p">,</span> <span class="n">ActivityKind</span><span class="p">.</span><span class="n">Producer</span><span class="p">))</span>
<span class="p">{</span>
    <span class="n">activity</span><span class="p">?.</span><span class="nf">SetTag</span><span class="p">(</span><span class="s">"user-notification-event.body"</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Body</span><span class="p">);</span>
    <span class="n">activity</span><span class="p">?.</span><span class="nf">SetTag</span><span class="p">(</span><span class="s">"user-notification-event.reference"</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Reference</span><span class="p">);</span>
    <span class="n">activity</span><span class="p">?.</span><span class="nf">SetTag</span><span class="p">(</span><span class="s">"user-notification-event.timestamp"</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Timestamp</span><span class="p">.</span><span class="nf">ToString</span><span class="p">(</span><span class="s">"o"</span><span class="p">));</span>

    <span class="n">sentNotifications</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">@event</span><span class="p">);</span>

    <span class="n">logger</span><span class="p">.</span><span class="nf">LogInformation</span><span class="p">(</span><span class="s">"User Notification Sent! {Reference}\nBody: {Body}\n@{Timestamp}"</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Body</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Reference</span><span class="p">,</span> <span class="n">@event</span><span class="p">.</span><span class="n">Timestamp</span><span class="p">);</span>

    <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<h3 id="outbox">Outbox</h3>

<p>Also in my Outbox implementation, because the <code class="language-plaintext highlighter-rouge">OutboxDispatcherHostedService</code> runs in a separate process, when it picks up an <code class="language-plaintext highlighter-rouge">OutboxItem</code> to dispatch, there is no trace data from the context which originally persisted the item, so I ended up serialising the telemetry context and saving it in a json string in the database so it could be rehydrated when dispatching, this means that the span persists across both phases before the <code class="language-plaintext highlighter-rouge">OutboxItem</code> is persisted and then afterwards when it is dispatched.</p>

<p>Code to serialise the telemetry context when persisting an individual <code class="language-plaintext highlighter-rouge">OutboxItem</code>, found in the <a href="https://github.com/andrewjpoole/event-sourced-but-flow-driven-example/blob/main/src/WeatherApp.Infrastructure/Outbox/OutboxRepository.cs">OutboxRepository</a>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">ActivitySource</span> <span class="n">Activity</span> <span class="p">=</span> <span class="k">new</span><span class="p">(</span><span class="k">nameof</span><span class="p">(</span><span class="n">OutboxRepository</span><span class="p">));</span>
<span class="k">private</span> <span class="k">static</span> <span class="k">readonly</span> <span class="n">TextMapPropagator</span> <span class="n">Propagator</span> <span class="p">=</span> <span class="n">Propagators</span><span class="p">.</span><span class="n">DefaultTextMapPropagator</span><span class="p">;</span>

<span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="kt">long</span><span class="p">&gt;</span> <span class="nf">Add</span><span class="p">(</span><span class="n">OutboxItem</span> <span class="n">outboxItem</span><span class="p">,</span> <span class="n">IDbTransactionWrapped</span><span class="p">?</span> <span class="n">transaction</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">//... prepare update query</span>
    <span class="k">using</span> <span class="p">(</span><span class="kt">var</span> <span class="n">activity</span> <span class="p">=</span> <span class="n">Activity</span><span class="p">.</span><span class="nf">StartActivity</span><span class="p">(</span><span class="s">"Outbox Item Insertion"</span><span class="p">,</span> <span class="n">ActivityKind</span><span class="p">.</span><span class="n">Producer</span><span class="p">))</span>
    <span class="p">{</span>
        <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;</span> <span class="n">telemetryDictionary</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
        <span class="k">if</span><span class="p">(</span><span class="n">activity</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span>
            <span class="n">Propagator</span><span class="p">.</span><span class="nf">Inject</span><span class="p">(</span><span class="k">new</span> <span class="nf">PropagationContext</span><span class="p">(</span><span class="n">activity</span><span class="p">.</span><span class="n">Context</span><span class="p">,</span> <span class="n">Baggage</span><span class="p">.</span><span class="n">Current</span><span class="p">),</span> <span class="n">telemetryDictionary</span><span class="p">,</span> <span class="p">(</span><span class="n">carrier</span><span class="p">,</span> <span class="n">key</span><span class="p">,</span> <span class="k">value</span><span class="p">)</span> <span class="p">=&gt;</span> 
            <span class="p">{</span>
                <span class="n">carrier</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="k">value</span><span class="p">);</span>
            <span class="p">});</span>

        <span class="n">parameters</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"@SerialisedTelemetry"</span><span class="p">,</span> <span class="n">JsonSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">telemetryDictionary</span><span class="p">));</span>

        <span class="kt">var</span> <span class="n">insertedOutboxItemId</span> <span class="p">=</span> <span class="k">await</span> <span class="n">connection</span><span class="p">.</span><span class="n">QuerySingleOrDefault</span><span class="p">&lt;</span><span class="kt">int</span><span class="p">&gt;(</span><span class="n">sql</span><span class="p">,</span> <span class="n">parameters</span><span class="p">,</span> <span class="n">transaction</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">insertedOutboxItemId</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Code to rehydrate just before sending an individual outbox item, found in the <a href="https://github.com/andrewjpoole/event-sourced-but-flow-driven-example/blob/main/src/WeatherApp.Infrastructure/Outbox/OutboxDispatcherHostedService.cs">OutboxDispatcherhostedService</a>:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Hydrate the telemetry context from item.SerialisedTelemetry...</span>
<span class="kt">var</span> <span class="n">parentContext</span> <span class="p">=</span> <span class="n">Propagator</span><span class="p">.</span><span class="nf">Extract</span><span class="p">(</span><span class="k">default</span><span class="p">,</span> <span class="n">item</span><span class="p">.</span><span class="n">SerialisedTelemetry</span><span class="p">,</span> <span class="p">(</span><span class="n">serialisedTelemetry</span><span class="p">,</span> <span class="n">key</span><span class="p">)</span> <span class="p">=&gt;</span> 
<span class="p">{</span>
    <span class="kt">var</span> <span class="n">telemetryDictionary</span> <span class="p">=</span> <span class="n">JsonSerializer</span><span class="p">.</span><span class="n">Deserialize</span><span class="p">&lt;</span><span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">string</span><span class="p">&gt;&gt;(</span><span class="n">serialisedTelemetry</span><span class="p">);</span>

    <span class="k">if</span> <span class="p">(</span><span class="n">telemetryDictionary</span> <span class="p">==</span> <span class="k">null</span> <span class="p">||</span> <span class="n">telemetryDictionary</span><span class="p">.</span><span class="n">Count</span> <span class="p">==</span> <span class="m">0</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">Enumerable</span><span class="p">.</span><span class="n">Empty</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;();</span>

    <span class="k">if</span><span class="p">(</span><span class="n">telemetryDictionary</span><span class="p">.</span><span class="nf">TryGetValue</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="k">value</span><span class="p">))</span>
        <span class="k">return</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="p">{</span> <span class="n">telemetryDictionary</span><span class="p">[</span><span class="n">key</span><span class="p">]</span> <span class="p">};</span>

    <span class="k">return</span> <span class="n">Enumerable</span><span class="p">.</span><span class="n">Empty</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;();</span>
<span class="p">});</span>
<span class="n">Baggage</span><span class="p">.</span><span class="n">Current</span> <span class="p">=</span> <span class="n">parentContext</span><span class="p">.</span><span class="n">Baggage</span><span class="p">;</span>

<span class="k">using</span> <span class="nn">var</span> <span class="n">activity</span> <span class="p">=</span> <span class="n">Activity</span><span class="p">.</span><span class="nf">StartActivity</span><span class="p">(</span><span class="s">"Dispatch Message"</span><span class="p">,</span> <span class="n">ActivityKind</span><span class="p">.</span><span class="n">Consumer</span><span class="p">,</span> <span class="n">parentContext</span><span class="p">.</span><span class="n">ActivityContext</span><span class="p">);</span>
<span class="k">await</span> <span class="n">messageSender</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">SerialisedData</span><span class="p">,</span> <span class="n">item</span><span class="p">.</span><span class="n">MessagingEntityName</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
<span class="k">await</span> <span class="n">outboxRepository</span><span class="p">.</span><span class="nf">AddSentStatus</span><span class="p">(</span><span class="n">OutboxSentStatusUpdate</span><span class="p">.</span><span class="nf">CreateSent</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">Id</span><span class="p">));</span>
<span class="n">logger</span><span class="p">.</span><span class="nf">LogDispatchedOutboxItem</span><span class="p">(</span><span class="n">item</span><span class="p">.</span><span class="n">Id</span><span class="p">);</span>
</code></pre></div></div>

<h2 id="ok-how-do-i-try-it">Ok, how do I try it?</h2>

<h3 id="setting-up-queryabletracecollector-in-your-aspire-project">Setting Up QueryableTraceCollector in your Aspire project</h3>

<ol>
  <li>Adding QueryableTraceCollector to Your Aspire Project</li>
</ol>

<p>add the <a href="https://www.nuget.org/packages/AJP.Aspire.Hosting.QueryableTraceCollector">hosting nuget package</a> to the 
<code class="language-plaintext highlighter-rouge">&lt;PackageReference Include="AJP.Aspire.Hosting.QueryableTraceCollector" Version="1.0.0" /&gt;</code></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">queryableTraceCollectorApiKey</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">[</span><span class="s">"QueryableTraceCollectorApiKey"</span><span class="p">]</span> <span class="p">??</span> <span class="s">"123456789"</span><span class="p">;</span> <span class="c1">// I add a local secret in VSCode...</span>
<span class="kt">var</span> <span class="n">queryabletracecollector</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">AddQueryableTraceCollector</span><span class="p">(</span><span class="s">"queryabletracecollector"</span><span class="p">,</span> <span class="n">queryableTraceCollectorApiKey</span><span class="p">)</span>
    <span class="p">.</span><span class="nf">WithExternalHttpEndpoints</span><span class="p">()</span>
    <span class="p">.</span><span class="nf">ExcludeFromManifest</span><span class="p">();</span>
</code></pre></div></div>
<p>This will add a container resource which runs the API.</p>

<ol>
  <li>Add the <a href="https://www.nuget.org/packages/AJP.Aspire.QueryableTraceCollector.Client/1.0.0">client integration nuget package</a>, probably to ServiceDefaults
<code class="language-plaintext highlighter-rouge">&lt;PackageReference Include="AJP.Aspire.QueryableTraceCollector.Client" Version="1.0.0" /&gt;</code></li>
</ol>

<p>Add</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="n">TBuilder</span> <span class="n">ConfigureOpenTelemetry</span><span class="p">&lt;</span><span class="n">TBuilder</span><span class="p">&gt;(</span><span class="k">this</span> <span class="n">TBuilder</span> <span class="n">builder</span><span class="p">)</span> <span class="k">where</span> <span class="n">TBuilder</span> <span class="p">:</span> <span class="n">IHostApplicationBuilder</span>
<span class="p">{</span>
    <span class="c1">//... usual stuff omitted</span>
    <span class="n">builder</span><span class="p">.</span><span class="nf">AddOpenTelemetryExporters</span><span class="p">();</span>

    <span class="c1">// Filter collected trace data by DisplayName to just the bits we're interested in, these can also be wired up through config instead if you prefer...</span>
    <span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddQueryableOtelCollectorExporter</span><span class="p">(</span><span class="n">builder</span><span class="p">.</span><span class="n">Configuration</span><span class="p">,</span> <span class="p">[</span><span class="s">"Outbox Item Insertion"</span><span class="p">,</span> <span class="s">"User Notification Sent"</span><span class="p">,</span> <span class="s">"Domain Event Insertion"</span><span class="p">]);</span> 

    <span class="k">return</span> <span class="n">builder</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>

<ol>
  <li>Assert against collected trace data in an Aspire test project</li>
</ol>

<p>I do it with a nice framework🙂 see my test, the second one in <a href="https://github.com/andrewjpoole/event-sourced-but-flow-driven-example/blob/main/tests/WeatherApp.Tests.Aspire.Integration/WeatherAppAspireIntegrationTests.cs">here</a></p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Test</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">PostWeatherData_EventuallyResultsIn_AUserNotificationBeingSent2</span><span class="p">()</span>
<span class="p">{</span>
    <span class="kt">var</span> <span class="p">(</span><span class="n">given</span><span class="p">,</span> <span class="n">when</span><span class="p">,</span> <span class="n">then</span><span class="p">)</span> <span class="p">=</span> <span class="p">(</span><span class="k">new</span> <span class="nf">Given</span><span class="p">(),</span> <span class="k">new</span> <span class="nf">When</span><span class="p">(),</span> <span class="k">new</span> <span class="nf">Then</span><span class="p">());</span>

    <span class="n">given</span><span class="p">.</span><span class="nf">WeHaveSetupTheAppHost</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">appHost</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeRunTheAppHost</span><span class="p">(</span><span class="n">appHost</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">app</span><span class="p">,</span> <span class="n">DefaultTimeout</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeCreateAnHttpClientForTheQueryableTraceCollector</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">appHost</span><span class="p">.</span><span class="n">Configuration</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">queryableTraceCollectorClient</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeClearAnyCollectedTraces</span><span class="p">(</span><span class="n">queryableTraceCollectorClient</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeCreateAnHtppClientForTheAPI</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">apiHttpClient</span><span class="p">,</span> <span class="n">DefaultTimeout</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeHaveSomeCollectedWeatherData</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">location</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">reference</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">requestId</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">collectedWeatherData</span><span class="p">);</span>

    <span class="n">when</span><span class="p">.</span><span class="nf">WeWrapTheWeatherDataInAnHttpRequest</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">httpRequest</span><span class="p">,</span> <span class="n">location</span><span class="p">,</span> <span class="n">reference</span><span class="p">,</span> <span class="n">requestId</span><span class="p">,</span> <span class="n">collectedWeatherData</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeSendTheRequest</span><span class="p">(</span><span class="n">apiHttpClient</span><span class="p">,</span> <span class="n">httpRequest</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">response</span><span class="p">);</span>

    <span class="n">then</span><span class="p">.</span><span class="nf">TheResponseShouldBe</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">);</span>
            
    <span class="n">when</span><span class="p">.</span><span class="nf">WeWaitWhilePollingForTheNotificationTrace</span><span class="p">(</span><span class="n">queryableTraceCollectorClient</span><span class="p">,</span> <span class="m">9</span><span class="p">,</span> <span class="s">"User Notification Sent"</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">traces</span><span class="p">);</span>
        
    <span class="n">then</span><span class="p">.</span><span class="nf">WeAssertAgainstTheTraces</span><span class="p">(</span><span class="n">traces</span><span class="p">,</span> <span class="n">traces</span> <span class="p">=&gt;</span> 
    <span class="p">{</span>
        <span class="n">traces</span><span class="p">.</span><span class="nf">AssertContainsDomainEventInsertionTag</span><span class="p">(</span><span class="s">"WeatherDataCollectionInitiated"</span><span class="p">);</span>
        <span class="n">traces</span><span class="p">.</span><span class="nf">AssertContainsDomainEventInsertionTag</span><span class="p">(</span><span class="s">"SubmittedToModeling"</span><span class="p">);</span>
        <span class="n">traces</span><span class="p">.</span><span class="nf">AssertContainsDomainEventInsertionTag</span><span class="p">(</span><span class="s">"ModelUpdated"</span><span class="p">);</span>
        
        <span class="n">traces</span><span class="p">.</span><span class="nf">AssertContainsDisplayName</span><span class="p">(</span><span class="s">"Outbox Item Insertion"</span><span class="p">);</span>

        <span class="n">traces</span><span class="p">.</span><span class="nf">AssertContains</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="n">DisplayName</span> <span class="p">==</span> <span class="s">"User Notification Sent"</span>
            <span class="p">&amp;&amp;</span> <span class="n">t</span><span class="p">.</span><span class="nf">ContainsTag</span><span class="p">(</span><span class="s">"user-notification-event.body"</span><span class="p">,</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span> <span class="p">==</span> <span class="s">"Dear user, your data has been submitted and included in our latest model"</span><span class="p">)</span>
            <span class="p">&amp;&amp;</span> <span class="n">t</span><span class="p">.</span><span class="nf">ContainsTag</span><span class="p">(</span><span class="s">"user-notification-event.reference"</span><span class="p">,</span> <span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span> <span class="p">==</span> <span class="n">reference</span><span class="p">),</span> 
            <span class="s">"Didn't find the expected user notification trace with the expected tags."</span><span class="p">);</span>            
    <span class="p">});</span>        
<span class="p">}</span>
</code></pre></div></div>

<p>That might seem like a large test for a blog post, but consider that it is testing an entire end-to-end flow (<a href="https://github.com/andrewjpoole/event-sourced-but-flow-driven-example/blob/main/README.md">described here in this readme</a>) and then compare it to your integration tests and end-to-end tests at work, then it starts to look nice and terse! The fact that it does all of its assertions consistently against a single source of truth, without the need to lots of complex timing and waiting makes a previously complex problem trivially simple🤓</p>

<h3 id="bonus-tip-1---if-you-need-to-ensure-that-an-api-call-is-not-traced">Bonus tip #1 - If you need to ensure that an API call is <em>not</em> traced</h3>

<p>You can just create a DelegatingHandler which literally nulls the current Activity. I use this to ensure that calls to QueryableTraceCollector are not themselves traced, otherwise we end up with infinite loops, ask me how I know 🤣</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">ClientHandlerWithTracingDisabled</span> <span class="p">:</span> <span class="n">DelegatingHandler</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="nf">ClientHandlerWithTracingDisabled</span><span class="p">(</span><span class="n">HttpMessageHandler</span> <span class="n">innerHandler</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">innerHandler</span><span class="p">){}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">HttpResponseMessage</span><span class="p">&gt;</span> <span class="nf">SendAsync</span><span class="p">(</span><span class="n">HttpRequestMessage</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Activity</span><span class="p">.</span><span class="n">Current</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
        <span class="k">return</span> <span class="k">await</span> <span class="k">base</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">protected</span> <span class="k">override</span> <span class="n">HttpResponseMessage</span> <span class="nf">Send</span><span class="p">(</span><span class="n">HttpRequestMessage</span> <span class="n">request</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Activity</span><span class="p">.</span><span class="n">Current</span> <span class="p">=</span> <span class="k">null</span><span class="p">;</span>
        <span class="k">return</span> <span class="k">base</span><span class="p">.</span><span class="nf">Send</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">cancellationToken</span><span class="p">);</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<h3 id="bonus-tip-2---customise-display-for-demos">Bonus tip #2 - Customise display for demos</h3>

<p>Recently I have been using VSCode for as much as possible and in particular Polyglot Notebooks for demonstrations. The Http cells are great, but for querying the QueryableTraceCollector’s API I have been using a CSharp cell where I can add an overridden <code class="language-plaintext highlighter-rouge">ToString()</code> method and customise the output using emojis like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// contents of CSharp Cell in Polyglot notebook</span>
<span class="k">using</span> <span class="nn">System.Net.Http</span><span class="p">;</span>
<span class="k">using</span> <span class="nn">System.Text.Json</span><span class="p">;</span>

<span class="k">public</span> <span class="k">class</span> <span class="nc">TraceData</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Resource</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">Source</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">DisplayName</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">TraceId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">string</span> <span class="n">SpanId</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>    
    <span class="k">public</span> <span class="n">Dictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span> <span class="n">Tags</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">override</span> <span class="kt">string</span> <span class="nf">ToString</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">thirdPart</span> <span class="p">=</span> <span class="kt">string</span><span class="p">.</span><span class="n">Empty</span><span class="p">;</span>
        <span class="k">if</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">==</span> <span class="s">"Domain Event Insertion"</span><span class="p">)</span>
            <span class="n">thirdPart</span> <span class="p">=</span> <span class="n">Tags</span><span class="p">[</span><span class="s">"domain-event.eventclassName"</span><span class="p">].</span><span class="nf">ToString</span><span class="p">().</span><span class="nf">Split</span><span class="p">(</span><span class="sc">'.'</span><span class="p">).</span><span class="nf">LastOrDefault</span><span class="p">();</span>

        <span class="k">if</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">==</span> <span class="s">"User Notification Sent"</span><span class="p">)</span>
            <span class="n">thirdPart</span> <span class="p">=</span> <span class="s">$"✉️ reference: </span><span class="p">{</span><span class="n">Tags</span><span class="p">[</span><span class="s">"user-notification-event.reference"</span><span class="p">].</span><span class="nf">ToString</span><span class="p">()}</span><span class="s">"</span><span class="p">;</span>

        <span class="k">if</span><span class="p">(</span><span class="n">DisplayName</span> <span class="p">==</span> <span class="s">"Outbox Item Insertion"</span><span class="p">)</span>
            <span class="n">thirdPart</span> <span class="p">=</span> <span class="s">$"📫 outbox id: </span><span class="p">{</span><span class="n">Tags</span><span class="p">[</span><span class="s">"outbox-item.Id"</span><span class="p">].</span><span class="nf">ToString</span><span class="p">()}</span><span class="s">"</span><span class="p">;</span>
                   
        <span class="k">return</span> <span class="s">$"</span><span class="p">{</span><span class="n">Resource</span><span class="p">.</span><span class="nf">PadRight</span><span class="p">(</span><span class="m">30</span><span class="p">,</span> <span class="sc">'-'</span><span class="p">)}</span><span class="s">&gt; </span><span class="p">{</span><span class="n">DisplayName</span><span class="p">.</span><span class="nf">PadRight</span><span class="p">(</span><span class="m">30</span><span class="p">,</span> <span class="sc">'-'</span><span class="p">)}</span><span class="s">&gt; </span><span class="p">{</span><span class="n">thirdPart</span><span class="p">}</span><span class="s">"</span><span class="p">;</span>
    <span class="p">}</span> 
        
<span class="p">}</span>

<span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HttpClient</span><span class="p">()</span> <span class="p">{</span> <span class="n">BaseAddress</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">Uri</span><span class="p">(</span><span class="s">"http://localhost:8000"</span><span class="p">),</span> <span class="n">DefaultRequestHeaders</span> <span class="p">=</span> <span class="p">{</span> <span class="p">{</span> <span class="s">"X-Api-Key"</span><span class="p">,</span> <span class="s">"insert-api-key-here"</span> <span class="p">}</span> <span class="p">}</span> <span class="p">};</span>
<span class="kt">var</span> <span class="n">response</span> <span class="p">=</span> <span class="k">await</span> <span class="n">client</span><span class="p">.</span><span class="nf">GetAsync</span><span class="p">(</span><span class="s">"traces"</span><span class="p">);</span>
<span class="kt">var</span> <span class="n">responseJson</span> <span class="p">=</span> <span class="k">await</span> <span class="n">response</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="nf">ReadAsStringAsync</span><span class="p">();</span>
<span class="n">JsonSerializer</span><span class="p">.</span><span class="n">Deserialize</span><span class="p">&lt;</span><span class="n">TraceData</span><span class="p">[</span><span class="k">]&gt;</span><span class="p">(</span><span class="n">responseJson</span><span class="p">,</span> <span class="n">JsonSerializerOptions</span><span class="p">.</span><span class="n">Web</span> <span class="p">).</span><span class="nf">Display</span><span class="p">();</span>
</code></pre></div></div>

<p><img src="/images//queryabletracecollector-polyglotnotebook-customise-output.png" alt="image" /></p>

<p>Which makes it much easier to spot things that matter.</p>

<h2 id="conclusions">Conclusions</h2>

<p>Asserting against trace data with .NET Aspire and QueryableTraceCollector elevates your integration tests, not only making them easier to write but also fairly trivial to run locally <em>and</em> less brittle😁 By helping us to move towards something like Observability-driven-development we can gain confidence that our distributed systems behave as intended—not just at the API level, but deep within its internals. Also by making the observability more useful, earlier in the loop, we end up with more supportable systems.</p>

<p>All of the code from this post can be found <a href="https://github.com/andrewjpoole/event-sourced-but-flow-driven-example">here</a></p>

<h3 id="best-practices">Best Practices</h3>

<ul>
  <li><strong>Isolate tests</strong>: If your QueryableTraceCollector persists between tests, be sure to call the DELETE /traces method to clear all trace data.</li>
  <li><strong>Use meaningful span names</strong>: This makes querying and asserting easier.</li>
  <li><strong>Assert on what matters</strong>: Focus on key operations, error handling, and context propagation.</li>
</ul>]]></content><author><name>Andrew Poole</name></author><summary type="html"><![CDATA[Integration Tests: How Not to Hate Them ❤️]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/testing-ai-generated-1.png" /><media:content medium="image" url="https://www.forkinthecode.net/images/testing-ai-generated-1.png" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Async method chaining in C#</title><link href="https://www.forkinthecode.net/2023/07/19/async-method-chaining.html" rel="alternate" type="text/html" title="Async method chaining in C#" /><published>2023-07-19T00:00:00+00:00</published><updated>2023-07-19T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2023/07/19/async-method-chaining</id><content type="html" xml:base="https://www.forkinthecode.net/2023/07/19/async-method-chaining.html"><![CDATA[<h1 id="async-method-chaining-in-c">Async Method Chaining in C#</h1>

<h2 id="tldr">TL/DR</h2>

<p>We recently had a large amount of fairly procedural logic performing multiple tasks in an API request handler, we wanted a way to split it up, but maintaining a really obvious flow and ease of code navigation. This is what we came up with applied to a contrived WeatherReport API:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">WeatherReport</span><span class="p">,</span> <span class="n">Failure</span><span class="p">&gt;&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="kt">string</span> <span class="n">requestedRegion</span><span class="p">,</span> <span class="n">DateTime</span> <span class="n">requestedDate</span><span class="p">)</span>
<span class="p">{</span>
    <span class="k">return</span> <span class="k">await</span> <span class="n">WeatherReport</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">requestedRegion</span><span class="p">,</span> <span class="n">requestedDate</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">regionValidator</span><span class="p">.</span><span class="n">ValidateRegion</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">dateChecker</span><span class="p">.</span><span class="n">CheckDate</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">CheckCache</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">weatherForecastGenerator</span><span class="p">.</span><span class="n">Generate</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>This code is wired-up directly a minimal API, where the <code class="language-plaintext highlighter-rouge">OneOf&lt;WeatherReport, Failure&gt;</code> result is converted to an HttpResponse and returned. These are async methods, chained together with a single return path. If you like the look of that, read on!</p>

<h2 id="background">Background</h2>

<h3 id="no-exceptions">No exceptions</h3>

<p>So in the API I mentioned earlier we are already using minimal API and the <code class="language-plaintext highlighter-rouge">FromServices</code> Attribute (<code class="language-plaintext highlighter-rouge">[FromServices]IXyzRequestHandler handler</code>) to move all processing from the API project to the Application project. This keeps the API project nice and thin.</p>

<p>For the return type of the <code class="language-plaintext highlighter-rouge">Handle()</code> method we use the excellent <a href="https://github.com/mcintyre321/OneOf">OneOf library</a>, which gives us discriminated unions in C#! In this case the return type is a <code class="language-plaintext highlighter-rouge">OneOf&lt;Sucess, Failure&gt;</code> where <code class="language-plaintext highlighter-rouge">Success</code> just represents success and <code class="language-plaintext highlighter-rouge">Failure</code> is a <code class="language-plaintext highlighter-rouge">OneOfBase</code> representing 3 or 4 specific Failure scenarios, these get mapped to various HttpResponses in the API. This means the method signature tells us everything we need to know about all possible outcomes and we are not resorting to using Exceptions to communicate non-exceptional behaviour. For instance, bad user input is not actually exceptional, its planned for and this approach allows us to define an <code class="language-plaintext highlighter-rouge">InvalidRequestFailure</code> which can be returned and will then be converted into a <code class="language-plaintext highlighter-rouge">400 BadRequest</code> HttpResponse.</p>

<p>Also because we may be interacting with external dependencies, the Handle method must be async, so the actual return type is <code class="language-plaintext highlighter-rouge">Task&lt;OneOf&lt;Sucess, Failure&gt;&gt;</code></p>

<h3 id="reducing-cognitive-load">Reducing Cognitive Load</h3>

<p>Initially, we considered using MediatR to refactor our logic, but it seemed overkill and looking through another repo where we were already using MediatR, it seemed quite hard to navigate. Each Request/Command Handler had to map its result into a new (but almost identical) Command/Request object with another Handler. So to figure out the path through the code, a fair amount of searching was nessecary.</p>

<p>A long while ago I did some work with Windows Workflow Foundation, which I really enjoyed. Code would be organised into functional chunks called Activities, each having In arguments, Out arguments and sometimes InOut arguments. The Activities would be arranged in a visual workflow, so the flow and ordering was really obvious. The striking thing about it, was that new team members could instantly find their way around and once inside an Activity it was immediately obvious what the scope of the task was, what inputs were available to use and what outputs would need to be set.</p>

<p>I wanted to find a way to replicate this declarative flow and a flavour of the functional isolation, because I want engineers to easily see what’s going on and find their way around. Our final solution shows the flow declaratively in one place and <code class="language-plaintext highlighter-rouge">[ctrl]+[f12]</code> takes you straight to the code in Visual Studio!</p>

<h2 id="how-its-used">How it’s used</h2>

<p>Here is the full version of the contrived WeatherReportRequestHandler example shown above:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">GetWeatherReportRequestHandler</span> <span class="p">:</span> <span class="n">IGetWeatherReportRequestHandler</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IRegionValidator</span> <span class="n">regionValidator</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IDateChecker</span> <span class="n">dateChecker</span><span class="p">;</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IWeatherForecastGenerator</span> <span class="n">weatherForecastGenerator</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">GetWeatherReportRequestHandler</span><span class="p">(</span><span class="n">IRegionValidator</span> <span class="n">regionValidator</span><span class="p">,</span> <span class="n">IDateChecker</span> <span class="n">dateChecker</span><span class="p">,</span> <span class="n">IWeatherForecastGenerator</span> <span class="n">weatherForecastGenerator</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">regionValidator</span> <span class="p">=</span> <span class="n">regionValidator</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="n">dateChecker</span> <span class="p">=</span> <span class="n">dateChecker</span><span class="p">;</span>
        <span class="k">this</span><span class="p">.</span><span class="n">weatherForecastGenerator</span> <span class="p">=</span> <span class="n">weatherForecastGenerator</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">WeatherReport</span><span class="p">,</span> <span class="n">Failure</span><span class="p">&gt;&gt;</span> <span class="nf">Handle</span><span class="p">(</span><span class="kt">string</span> <span class="n">requestedRegion</span><span class="p">,</span> <span class="n">DateTime</span> <span class="n">requestedDate</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="k">await</span> <span class="n">WeatherReport</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">requestedRegion</span><span class="p">,</span> <span class="n">requestedDate</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="n">regionValidator</span><span class="p">.</span><span class="nf">ValidateRegion</span><span class="p">(</span><span class="n">report</span><span class="p">))</span>
            <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="n">dateChecker</span><span class="p">.</span><span class="nf">CheckDate</span><span class="p">(</span><span class="n">report</span><span class="p">))</span>
            <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="nf">CheckCache</span><span class="p">(</span><span class="n">report</span><span class="p">))</span>
            <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="n">weatherForecastGenerator</span><span class="p">.</span><span class="nf">Generate</span><span class="p">(</span><span class="n">report</span><span class="p">));</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">WeatherReport</span><span class="p">,</span> <span class="n">Failure</span><span class="p">&gt;&gt;</span> <span class="nf">CheckCache</span><span class="p">(</span><span class="n">WeatherReport</span> <span class="n">report</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// Check and populate from a cache etc...</span>
        <span class="c1">// Methods from anywhere can be chained as long as they have the correct signature...</span>
        <span class="k">return</span> <span class="n">report</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>A static method named <code class="language-plaintext highlighter-rouge">Create()</code> returns an initialised <code class="language-plaintext highlighter-rouge">WeatherReport</code> object, but it actually returns a <code class="language-plaintext highlighter-rouge">Task&lt;OneOf&lt;WeatherReport, Failure&gt;&gt;</code> we’ll see why in a moment. The <code class="language-plaintext highlighter-rouge">WeatherReport</code> object contains any required state and crucially represents Success when returned.</p>

<p>To be chained, a method need only have the correct return type, in this case a <code class="language-plaintext highlighter-rouge">Task&lt;OneOf&lt;WeatherReport, Failure&gt;&gt;</code>. The chained method will probably receive a <code class="language-plaintext highlighter-rouge">WeatherReport</code> as an argument so it can read some state, perform its task, possibly set some resulting state and then crucially it should return the <code class="language-plaintext highlighter-rouge">WeatherReport</code> object if successful <em>or</em> a derivative of <code class="language-plaintext highlighter-rouge">Failure</code> if not.</p>

<p>Note the methods can live anywhere, they might be local or live on services injected from IoC, they just need the correct signature.</p>

<p>The chaining is possible because of an extension method named <code class="language-plaintext highlighter-rouge">Then</code> (shown below) which extends a <code class="language-plaintext highlighter-rouge">Task&lt;OneOf&lt;T, TFailure&gt;&gt;</code>. In the case above the <code class="language-plaintext highlighter-rouge">T</code> is the <code class="language-plaintext highlighter-rouge">WeatherReport</code> and <code class="language-plaintext highlighter-rouge">TFailure</code> is the <code class="language-plaintext highlighter-rouge">Failure</code> class mentioned above. This is why the <code class="language-plaintext highlighter-rouge">Create()</code> method and all of the other methods in the chain must return <code class="language-plaintext highlighter-rouge">Task&lt;OneOf&lt;WeatherReport, Failure&gt;&gt;</code>. The compiler infers what the Types <code class="language-plaintext highlighter-rouge">T</code> and <code class="language-plaintext highlighter-rouge">TFailure</code> are from the first method in the chain.</p>

<p>In this version you can see the <code class="language-plaintext highlighter-rouge">WeatherReport</code> variable named <code class="language-plaintext highlighter-rouge">report</code> being explicitly passed into each chained method, if the chained methods only have a single <code class="language-plaintext highlighter-rouge">T</code> argument then you can use the C# feature method group conversion to delegate, making the code even more terse and easily readable:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="n">regionValidator</span><span class="p">.</span><span class="nf">ValidateRegion</span><span class="p">(</span><span class="n">report</span><span class="p">))</span>
<span class="c1">// becomes</span>
<span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">regionValidator</span><span class="p">.</span><span class="n">ValidateRegion</span><span class="p">)</span>
</code></pre></div></div>
<p>This is shown in the TLDR section at the top.</p>

<p>As with any lambda expressions in C#, the func containing the chained method can capture any outer variables in scope e.g.</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kt">var</span> <span class="n">validationSettings</span> <span class="p">=</span> <span class="k">new</span> <span class="n">ValidationSettings</span><span class="p">{...}</span>
<span class="p">...</span>
<span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">report</span> <span class="p">=&gt;</span> <span class="n">regionValidator</span><span class="p">.</span><span class="nf">ValidateRegion</span><span class="p">(</span><span class="n">report</span><span class="p">,</span> <span class="n">validationSettings</span><span class="p">))</span>
</code></pre></div></div>

<p>Out variables can also be used to return state from a chained method and passed into subsequent chained methods or consumed in the method containing the chain.</p>

<p>We have had success using a record for the <code class="language-plaintext highlighter-rouge">T</code> where some properties are set initially in our <code class="language-plaintext highlighter-rouge">Create()</code> method and other nullable properties start life as null, but are later set while creating a new version of the record using the <code class="language-plaintext highlighter-rouge">with</code> keyword.</p>

<h2 id="how-it-works">How it works</h2>

<p>Here is the simplest version of the extension method <code class="language-plaintext highlighter-rouge">Then</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;</span> <span class="n">Then</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;(</span>
  <span class="k">this</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;</span> <span class="n">currentJobResult</span><span class="p">,</span>
  <span class="n">Func</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;&gt;</span> <span class="n">nextJob</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Inspect result of (probably already awaited) currentJobResult, if its a TFailure return it...</span>
    <span class="kt">var</span> <span class="n">TOrFailure</span> <span class="p">=</span> <span class="k">await</span> <span class="n">currentJobResult</span><span class="p">;</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">TOrFailure</span><span class="p">.</span><span class="n">IsT1</span><span class="p">)</span>
        <span class="k">return</span> <span class="n">TOrFailure</span><span class="p">;</span>

    <span class="c1">// ...Otherwise do your next job</span>
    <span class="kt">var</span> <span class="n">currentT</span> <span class="p">=</span> <span class="n">TOrFailure</span><span class="p">.</span><span class="n">AsT0</span><span class="p">;</span>
    <span class="k">return</span> <span class="k">await</span> <span class="nf">nextJob</span><span class="p">(</span><span class="n">currentT</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>So the first job is to inspect the result of the previous job in the chain, we await it, but are pretty sure that its already been awaited and therefore the Result is already available. Note this is fine because we are using the full blown <code class="language-plaintext highlighter-rouge">Task</code>, if it were <code class="language-plaintext highlighter-rouge">ValueTask</code> we would not be able to await a second time. The OneOf library has methods for us to determine if if the Result contains the <code class="language-plaintext highlighter-rouge">T</code> (<code class="language-plaintext highlighter-rouge">WeatherReport</code> in this case) or <code class="language-plaintext highlighter-rouge">TFailure</code> (a <code class="language-plaintext highlighter-rouge">Failure</code> in this case). <code class="language-plaintext highlighter-rouge">IsT0()</code> will return true if the object contains the first possiblity in the discriminated union, <code class="language-plaintext highlighter-rouge">IsT1()</code> will return true for the second item etc.</p>

<p>If the result contains a <code class="language-plaintext highlighter-rouge">TFailure</code> from earlier in the chain we <em>immediately</em> return that <code class="language-plaintext highlighter-rouge">Failure</code> <em>without</em> performing our Task, all of the following <code class="language-plaintext highlighter-rouge">Then's</code> in the chain do the same. This means the first <code class="language-plaintext highlighter-rouge">Failure</code> returned by a chained task is returned and no more chained tasks are executed.</p>

<p>Otherwise if the Result was successful, which means it contained a <code class="language-plaintext highlighter-rouge">T</code> (<code class="language-plaintext highlighter-rouge">WeatherReport</code> in this case) then we should call and await the <code class="language-plaintext highlighter-rouge">Func</code> <code class="language-plaintext highlighter-rouge">nextJob</code> passing in the <code class="language-plaintext highlighter-rouge">T</code> (<code class="language-plaintext highlighter-rouge">WeatherReport</code> in this case). This is how the chain is continued.</p>

<h3 id="what-if-something-goes-wrong">What if something goes wrong?</h3>

<p>We had a case where we were creating two transactions, one after the other in the chain, but if the first succeeded and the second failed, we needed a way to cancel the first transaction. Initially this code was hidden in the second transaction creation method, but a team member pointed out that was counter-intuitive. To solve this problem a second overload of the <code class="language-plaintext highlighter-rouge">Then</code> method is provided which takes a second Func called <code class="language-plaintext highlighter-rouge">onFailure</code> as an argument. We inspect the Result of <code class="language-plaintext highlighter-rouge">nextJob</code> in the same way and if it fails, we invoke and await <code class="language-plaintext highlighter-rouge">onFailure</code> before returning the <code class="language-plaintext highlighter-rouge">TFailure</code> as before.</p>

<p>Here is the overload of the extension method <code class="language-plaintext highlighter-rouge">Then</code> with <code class="language-plaintext highlighter-rouge">onFailure</code>:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;</span> <span class="n">Then</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;(</span>
  <span class="k">this</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;</span> <span class="n">currentJobResult</span><span class="p">,</span>
  <span class="n">Func</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">OneOf</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">&gt;&gt;&gt;</span> <span class="n">nextJob</span><span class="p">,</span>
  <span class="n">Func</span><span class="p">&lt;</span><span class="n">T</span><span class="p">,</span> <span class="n">TFailure</span><span class="p">,</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">TFailure</span><span class="p">&gt;&gt;</span> <span class="n">onFailure</span><span class="p">)</span>
<span class="p">{</span>
    <span class="c1">// Inspect result of (probably already awaited) currentJobResult, if its a TFailure return it...</span>
        <span class="kt">var</span> <span class="n">TOrFailure</span> <span class="p">=</span> <span class="k">await</span> <span class="n">currentJobResult</span><span class="p">;</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">TOrFailure</span><span class="p">.</span><span class="n">IsT1</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">TOrFailure</span><span class="p">;</span>

        <span class="c1">// ...Otherwise do your next job ... </span>
        <span class="kt">var</span> <span class="n">currentT</span> <span class="p">=</span> <span class="n">TOrFailure</span><span class="p">.</span><span class="n">AsT0</span><span class="p">;</span>
        <span class="kt">var</span> <span class="n">result</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">nextJob</span><span class="p">(</span><span class="n">currentT</span><span class="p">);</span>

        <span class="c1">// If next job returned a T (Success) return it...</span>
        <span class="k">if</span> <span class="p">(</span><span class="n">result</span><span class="p">.</span><span class="n">IsT0</span><span class="p">)</span>
            <span class="k">return</span> <span class="n">result</span><span class="p">;</span>        
        
        <span class="c1">// Otherwise invoke onFailure and return the final resulting TFailure...</span>
        <span class="kt">var</span> <span class="n">finalFailure</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">onFailure</span><span class="p">(</span><span class="n">currentT</span><span class="p">,</span> <span class="n">result</span><span class="p">.</span><span class="n">AsT1</span><span class="p">);</span>
        <span class="k">return</span> <span class="n">finalFailure</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>It can be used like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">return</span> <span class="k">await</span> <span class="n">PaymentDetails</span><span class="p">.</span><span class="nf">Create</span><span class="p">(</span><span class="n">request</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">validator</span><span class="p">.</span><span class="nf">ValidateRequest</span><span class="p">(</span><span class="n">d</span><span class="p">))</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">paymentRepository</span><span class="p">.</span><span class="nf">Save</span><span class="p">(</span><span class="n">d</span><span class="p">))</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">transactionService</span><span class="p">.</span><span class="nf">CreateDebitTransaction</span><span class="p">(</span><span class="n">d</span><span class="p">))</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">transactionService</span><span class="p">.</span><span class="nf">CreateCreditTransaction</span><span class="p">(</span><span class="n">d</span><span class="p">),</span> <span class="n">onFailure</span><span class="p">:</span> <span class="n">d</span><span class="p">,</span> <span class="n">f</span> <span class="p">=&gt;</span> <span class="n">transactionService</span><span class="p">.</span><span class="nf">CancelDebitTransaction</span><span class="p">(</span><span class="n">d</span><span class="p">,</span> <span class="n">f</span><span class="p">))</span>
        <span class="p">.</span><span class="nf">Then</span><span class="p">(</span><span class="n">d</span> <span class="p">=&gt;</span> <span class="n">eventDispatcher</span><span class="p">.</span><span class="nf">Dispatch</span><span class="p">(</span><span class="n">d</span><span class="p">));</span>
</code></pre></div></div>

<p>We also have a method named <code class="language-plaintext highlighter-rouge">IfThen()</code> which takes an additional <code class="language-plaintext highlighter-rouge">func&lt;T, bool&gt;</code> named <code class="language-plaintext highlighter-rouge">condition</code> so that the <code class="language-plaintext highlighter-rouge">nextJob</code> will only be invoked if <code class="language-plaintext highlighter-rouge">condition</code> evaluates to True; I’m sure there are other variations which will be added.</p>

<h2 id="conclusion">Conclusion</h2>

<p>So if you also have multiple tasks to perform off the back of an API request or when handling a Service Bus message etc, maybe consider this method of chaining methods together. Maintain a single return path, place the methods wherever they best fit and make life easy for your team by expressing declaratively the flow of tasks with super-easy code navigation.</p>

<p>This code is avilable in a <a href="https://www.nuget.org/packages/OneOf.Chaining">Nuget package</a> and in this <a href="https://github.com/andrewjpoole/OneOf.Chaining">GitHib repository</a>, but its basically a few small extension methods, so copy/paste away!</p>

<p>Hope you found this interesting, thanks for reading :)</p>]]></content><author><name>Andrew Poole</name></author><summary type="html"><![CDATA[Async Method Chaining in C#]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/chain-shiny-portrait.jpg" /><media:content medium="image" url="https://www.forkinthecode.net/images/chain-shiny-portrait.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Given, When and Then helper classes for testing</title><link href="https://www.forkinthecode.net/2023/07/18/given-when-then-helper-classes-for-component-tests.html" rel="alternate" type="text/html" title="Given, When and Then helper classes for testing" /><published>2023-07-18T00:00:00+00:00</published><updated>2023-07-18T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2023/07/18/given-when-then-helper-classes-for-component-tests</id><content type="html" xml:base="https://www.forkinthecode.net/2023/07/18/given-when-then-helper-classes-for-component-tests.html"><![CDATA[<h1 id="given-when-and-then-helperclasses-for-testing">Given, When and Then helper classes for testing</h1>

<h2 id="tldr">TL/DR</h2>

<p>This post introduces a method of organising test code into shared, reusable chunks, enabling complex tests to be expressed in a terse english-like fashion, which looks like this:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">Return_badRequest_when_request_is_invalid</span><span class="p">()</span>
<span class="p">{</span>
    <span class="n">Given</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">TheTransactionsApiCreateEndpointWillReturn</span><span class="p">(</span><span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">OK</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeHaveAnInvalidPaymentRequest</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">invalidPaymentRequest</span><span class="p">,</span> <span class="n">currency</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">TheServerIsStarted</span><span class="p">();</span>

    <span class="n">When</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">WeWrapThePaymentRequestInHttpRequestMessage</span><span class="p">(</span><span class="n">invalidPaymentRequest</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">httpRequestMessage</span><span class="p">)</span>
        <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">WeSendTheMessageToTheApi</span><span class="p">(</span><span class="n">httpRequestMessage</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">response</span><span class="p">);</span>
    
    <span class="k">using</span> <span class="p">(</span><span class="k">new</span> <span class="nf">AssertionScope</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="n">Then</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">TheResponseCodeShouldBe</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="n">HttpStatusCode</span><span class="p">.</span><span class="n">BadRequest</span><span class="p">)</span>
            <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">TheBodyShouldNotBeEmpty</span><span class="p">(</span><span class="n">response</span><span class="p">,</span> <span class="k">out</span> <span class="kt">var</span> <span class="n">body</span><span class="p">)</span>
            <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">TheBodyShouldContainAProblemDetails</span><span class="p">(</span><span class="n">body</span><span class="p">,</span> <span class="n">details</span> <span class="p">=&gt;</span> <span class="n">details</span><span class="p">.</span><span class="n">Errors</span><span class="p">.</span><span class="n">Count</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="m">1</span><span class="p">))</span>
            <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">APaymentRecordWasNotSaved</span><span class="p">()</span>
            <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">NoPaymentStatusRecordsWereSaved</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Hopefully you agree that while still outlining precisely what is being set up, executed and asserted against, this test is easy to understand. In fact you could probably show it to your Product Owner without requiring too much explanation.</p>

<h2 id="background">Background</h2>

<p>I have alluded to this pattern in previous blog posts, but I’ve been using it for a while now on many different projects, and it continues to be extremely useful so I thought it deserved a blog in its own right.</p>

<p>In our team we favour using Component tests to create the majority of our code coverage, filling in with Unit tests where necessary. Then we add minimal Integration tests to prove out integrations with external services and finally end-to-end tests to test flows from start to finish. I guess this roughly aligns to the testing trophy idea as opposed to the testing triangle.</p>

<p>Our Component tests are like internal Integration tests, we we aim to exercise as much of the app as possible, just mocking the external dependencies at the outermost point. So, for example, we use WebApplicationFactory<TEntryPoint> to test from the Program onwards, setting up Mocks and switching them in place of external service interfaces, such as database or service bus connections. The rest of the real services/components under test obviously do not know that the external dependencies are mocked.</TEntryPoint></p>

<p>This kind of test provides lots of value, including a relatively realistic local debugging experience and finding issues that traditional unit testing would not be expected to find. For instance, if an injected service was not registered in the IoC container or a required config value was missing, these tests would not pass.</p>

<p>There are downsides to this approach; there is a fair amount of code to initially set everything up and this in turn makes it hard to do TDD. The tests themselves can also become quite large unless you have a strategy for organising and sharing code across tests…</p>

<h2 id="given-when-and-then-classes">Given, When and Then classes</h2>

<p>In order to solve some of those problems, we separate out the arrange, act and assert parts of a test into <code class="language-plaintext highlighter-rouge">Given</code>, <code class="language-plaintext highlighter-rouge">When</code> and <code class="language-plaintext highlighter-rouge">Then</code> classes, every method on each of these classes returns itself, which results in a nice fluent interface making the tests shorter and improving readability. This approach encourages code sharing and consistency across tests.</p>

<h3 id="the-given-class">The <code class="language-plaintext highlighter-rouge">Given</code> class</h3>

<p>is responsible for the ‘arrange’ part of the test. It contains methods for setting up behaviour on the Mocks, creating payloads and/or other bits of test data. When setting up Mocked behaviours, I like to name methods using the future tense e.g. <code class="language-plaintext highlighter-rouge">TheTransactionsApiWillReturnTheStatusCode(HttpStatusCode.BadRequest)</code></p>

<h3 id="the-when-class">The <code class="language-plaintext highlighter-rouge">When</code> class</h3>

<p>is responsible for the ‘act’ part of the test. It contains methods for kicking off the process being tested, so sending a request to an API, sending a service bus message, inserting data into a database or creating events in an event store etc.</p>

<h3 id="the-then-class">The <code class="language-plaintext highlighter-rouge">Then</code> class</h3>

<p>is responsible for the ‘assert’ part of the test. It contains methods for making assertions. One useful trick is to have a method which takes an Action to allow the tests to do their own assertions with any assertion library, for example you might have a method named <code class="language-plaintext highlighter-rouge">TheHttpResponseContainsABody(HttpResponseMessage response, Action&lt;string&gt; assertAgainstBody)</code> this can then be used with  FluentAssertions like this: <code class="language-plaintext highlighter-rouge">And.TheHttpResponseContainsABody(response, body =&gt; body.Should().Be("Alive!"))</code></p>

<p>In the above example, the whole <code class="language-plaintext highlighter-rouge">Then</code> section is wrapped in a <code class="language-plaintext highlighter-rouge">using (new AssertionScope())</code> this means that all assertions will be evaluated before any failed assertions cause the test to fail, so all of the failed assertions will be reported, rather than just the first one.</p>

<h3 id="shared-stuff">Shared stuff</h3>

<p>All three classes share an instance of whatever owns the Mocks and useful properties or fields, let’s call this the context. Each class has a static method <code class="language-plaintext highlighter-rouge">UsingThe()</code> which assigns this shared state object and returns a new <code class="language-plaintext highlighter-rouge">Given</code>, <code class="language-plaintext highlighter-rouge">When</code> or <code class="language-plaintext highlighter-rouge">Then</code>. Each class also has a dummy <code class="language-plaintext highlighter-rouge">And</code> property which just returns itself meaning the tests read more like English sentences.</p>

<h3 id="out-variables">Out variables!</h3>

<p>So no-one likes out variables, myself included, but here they offer a way of defining state inline without breaking the flow/readability of the tests, which I think really works well. It also makes the variables easy to trace through the test steps.</p>

<h3 id="some-code">Some code</h3>

<p>Simplified example <code class="language-plaintext highlighter-rouge">Given</code>, <code class="language-plaintext highlighter-rouge">When</code> and <code class="language-plaintext highlighter-rouge">Then</code> classes are included below to get you going. These classes are necessarily specific to the app under test, so we find we start from scratch each time, here is <a href="https://gist.github.com/andrewjpoole/039ae07be0bc3534cda6383780d5a945">a handy gist</a> containing the bare bones classes ready to add methods to.</p>

<p>Here is an example of a Given class with methods for setting up testing an API:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Given</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Given</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">apiWebApplicationFactory</span> <span class="p">=</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>
        <span class="n">apiWebApplicationFactory</span><span class="p">.</span><span class="n">MockWeatherReportFetcher</span><span class="p">.</span><span class="n">Invocations</span><span class="p">.</span><span class="nf">Clear</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">Given</span> <span class="nf">UsingThe</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">);</span>
    <span class="k">public</span> <span class="n">Given</span> <span class="n">And</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span>
    
    <span class="k">public</span> <span class="n">Given</span> <span class="nf">TheWeatherReportFetcherApiEndpointWillReturn</span><span class="p">(</span><span class="n">HttpStatusCode</span> <span class="n">statusCode</span><span class="p">,</span> <span class="n">Refit</span><span class="p">.</span><span class="n">ProblemDetails</span><span class="p">?</span> <span class="n">problemDetails</span> <span class="p">=</span> <span class="k">null</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">apiWebApplicationFactory</span><span class="p">.</span><span class="n">MockWeatherReportFetcher</span>
            <span class="p">.</span><span class="nf">SetupRequest</span><span class="p">(</span><span class="n">HttpMethod</span><span class="p">.</span><span class="n">Get</span><span class="p">,</span> <span class="n">r</span> <span class="p">=&gt;</span> <span class="n">r</span><span class="p">.</span><span class="n">RequestUri</span> <span class="p">==</span> <span class="n">someUri</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">ReturnsResponse</span><span class="p">(</span><span class="n">statusCode</span><span class="p">,</span> <span class="k">new</span> <span class="nf">StringContent</span><span class="p">(</span><span class="n">JsonSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">problemDetails</span><span class="p">),</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">));</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>    

    <span class="k">public</span> <span class="n">Given</span> <span class="nf">WeHaveAWeatherReportRequestPayload</span><span class="p">(</span><span class="k">out</span> <span class="n">WeatherForecastRequest</span> <span class="n">requestPayload</span><span class="p">,</span> <span class="kt">string</span> <span class="n">currency</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">paymentRequest</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">WeatherForecastRequest</span><span class="p">(</span>
            <span class="c1">// populate request here...</span>
        <span class="p">);</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>    

    <span class="k">public</span> <span class="n">Given</span> <span class="nf">TheServerIsStarted</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">apiWebApplicationFactory</span><span class="p">.</span><span class="nf">Start</span><span class="p">();</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Here is an example of a When class with methods for testing an API:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">When</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">When</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">apiWebApplicationFactory</span> <span class="p">=</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">When</span> <span class="nf">UsingThe</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">);</span>
    <span class="k">public</span> <span class="n">When</span> <span class="n">And</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span>

    <span class="k">public</span> <span class="n">When</span> <span class="nf">WeWrapTheRequestInHttpRequestMessage</span><span class="p">(</span><span class="n">WeatherForecastRequest</span> <span class="n">requestPayload</span><span class="p">,</span> <span class="k">out</span> <span class="n">HttpRequestMessage</span> <span class="n">httpRequest</span><span class="p">)</span>
    <span class="p">{</span>        
        <span class="n">httpRequest</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HttpRequestMessage</span><span class="p">(</span><span class="n">HttpMethod</span><span class="p">.</span><span class="n">Post</span><span class="p">,</span> <span class="n">DomesticOrchestratorApiWebApplicationFactory</span><span class="p">.</span><span class="n">DomesticPaymentUri</span><span class="p">);</span>
        <span class="n">httpRequest</span><span class="p">.</span><span class="n">Headers</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"AdditionalRequiredHeaderName"</span><span class="p">,</span> <span class="n">JsonSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">someValue</span><span class="p">));</span>
        <span class="n">httpRequest</span><span class="p">.</span><span class="n">Content</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">StringContent</span><span class="p">(</span><span class="n">JsonSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">requestPayload</span><span class="p">),</span> <span class="n">Encoding</span><span class="p">.</span><span class="n">UTF8</span><span class="p">,</span> <span class="s">"application/json"</span><span class="p">);</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">When</span> <span class="nf">WeSendTheMessageToTheApi</span><span class="p">(</span><span class="n">HttpRequestMessage</span> <span class="n">httpRequest</span><span class="p">,</span> <span class="k">out</span> <span class="n">HttpResponseMessage</span> <span class="n">response</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">response</span> <span class="p">=</span> <span class="n">apiWebApplicationFactory</span><span class="p">.</span><span class="n">HttpClient</span><span class="p">.</span><span class="nf">SendAsync</span><span class="p">(</span><span class="n">httpRequest</span><span class="p">).</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h4 id="async-methods">Async methods</h4>

<p>The methods on these classes are necessarily all ordinary synchronous methods, otherwise the await keyword would prevent the method chaining. So to execute some asynchronous process like calling an API we do use <code class="language-plaintext highlighter-rouge">.GetAwaiter().GetResult();</code> The reason I’m Ok with this is that the test code being synchronous actually simplifies things. If the test code and the code-under-test were both async, I think there would be more chance of race conditions and more complex code required to prevent them. This way, if we need to wait for an async process to complete, e.g. for a service bus handler to finish handling a message, we can add a method <code class="language-plaintext highlighter-rouge">Then... And.WeWaitSomeTimeForProcessingToComplete(timeToWaitInMilliSeconds: 500)</code></p>

<p>Here is an example of a Then class with methods for testing an API:</p>
<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Then</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Then</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">this</span><span class="p">.</span><span class="n">apiWebApplicationFactory</span> <span class="p">=</span> <span class="n">apiWebApplicationFactory</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">Then</span> <span class="nf">UsingThe</span><span class="p">(</span><span class="n">WeatherReportApiWebApplicationFactory</span> <span class="n">apiWebApplicationFactory</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">apiWebApplicationFactory</span><span class="p">);</span>
    <span class="k">public</span> <span class="n">Then</span> <span class="n">And</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheResponseCodeShouldBe</span><span class="p">(</span><span class="n">HttpResponseMessage</span> <span class="n">response</span><span class="p">,</span> <span class="n">HttpStatusCode</span> <span class="n">code</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">response</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">NotBeNull</span><span class="p">();</span>
        <span class="n">response</span><span class="p">.</span><span class="n">StatusCode</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">code</span><span class="p">);</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheBodyShouldNotBeEmpty</span><span class="p">(</span><span class="n">HttpResponseMessage</span> <span class="n">response</span><span class="p">,</span> <span class="n">Action</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;</span> <span class="n">assertAgainstBody</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">body</span> <span class="p">=</span> <span class="n">response</span><span class="p">.</span><span class="n">Content</span><span class="p">.</span><span class="nf">ReadAsStringAsync</span><span class="p">().</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
        <span class="nf">assertAgainstBody</span><span class="p">(</span><span class="n">body</span><span class="p">);</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="in-conclusion">In conclusion</h2>

<p>So there it is, a simple strategy for organising your test code with, so lightweight it doesn’t even constitute a framework! Hope you find it helpful and thanks for taking the time to read :)</p>]]></content><author><name>Andrew Poole</name></author><summary type="html"><![CDATA[Given, When and Then helper classes for testing]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/gherkin.jpg" /><media:content medium="image" url="https://www.forkinthecode.net/images/gherkin.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">CSharp SQL Tests</title><link href="https://www.forkinthecode.net/2022/04/11/csharp-sql-tests.html" rel="alternate" type="text/html" title="CSharp SQL Tests" /><published>2022-04-11T00:00:00+00:00</published><updated>2022-04-11T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2022/04/11/csharp-sql-tests</id><content type="html" xml:base="https://www.forkinthecode.net/2022/04/11/csharp-sql-tests.html"><![CDATA[<p>TL/DR You know you should be testing T-SQL code in stored procedures/views and if you’re underwhelmed by the T-Sql based frameworks available you might like to use a nice fluent C# framework and even use markdown table syntax to define data! If so, read on…</p>

<h2 id="background">Background</h2>

<p>At ClearBank, we are currently preferring Dapper to Entity Framework, this means we are writing more stored procedures and naturally want to cover those stored procedures with tests. At first, we just used xUnit tests, which worked perfectly well but the setup and teardown of test data proved a little cumbersome. We then tried switching approach to the tSQLt framework, which again worked perfectly well and had the added advantage of running against a temporary database instance with a DacPac project deployed and running each test in its own SQL transaction. However, as developers spoilt by the lovely syntax of modern languages like C#, we found the tSQLt tests quite unpleasant to both read and write.</p>

<p>I thought there must be a better way to combine the best bits of both worlds and this SQL test framework is what I came up with. Hopefully, it will be useful to other people too.</p>

<h2 id="in-a-nutshell">In a nutshell</h2>

<p>The framework allows tests to be written in C# using familiar test frameworks (xUnit is used in the examples). The tests can be run against localDb or some other SQL server. A DacPac can optionally be deployed. Each test is isolated from the other tests. Given, When and Then helper classes are included to and also a way to define tabular data for test data setup and/or assertions. More on those things later. We are also using this package to test repository classes in addition to stored procedures.</p>

<p>A test looks like this:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">spFetchOrderById_returns_an_order_matching_the_supplied_order_Id</span><span class="p">()</span>
<span class="p">{</span>
    <span class="c1">// the numbers in the comments relate to the explanation below: </span>
    <span class="k">new</span> <span class="nf">LocalDbTestContext</span><span class="p">(</span><span class="s">"TestDatabaseName"</span><span class="p">)</span> <span class="c1">// 1</span>
        <span class="p">.</span><span class="nf">DeployDacpac</span><span class="p">()</span>                        <span class="c1">// 2</span>
        <span class="p">.</span><span class="nf">RunTest</span><span class="p">((</span><span class="n">connection</span><span class="p">,</span> <span class="n">transaction</span><span class="p">)</span> <span class="p">=&gt;</span>  <span class="c1">// 3</span>
    <span class="p">{</span>
        <span class="c1">// 4</span>
        <span class="kt">var</span> <span class="n">order</span> <span class="p">=</span> <span class="s">@"
        | Id | Customers_Id | DateCreated | Product | Quantity | Price | Notes       |
        | -- | ------------ | ----------- | ------- | -------- | ----- | ----------- |
        | 23 | 1            | 2021/07/21  | Apples  | 21       | 5.29  | emptyString |"</span><span class="p">;</span>

        <span class="n">Given</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">_context</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">TheFollowingSqlStatementIsExecuted</span><span class="p">(</span>
                <span class="s">"ALTER TABLE Orders DROP CONSTRAINT FK_Orders_Customers;"</span><span class="p">)</span> <span class="c1">// 5</span>
            <span class="p">.</span><span class="n">And</span><span class="p">.</span><span class="nf">TheFollowingDataExistsInTheTable</span><span class="p">(</span><span class="s">"Orders"</span><span class="p">,</span> <span class="n">order</span><span class="p">);</span> <span class="c1">// 6</span>

        <span class="n">When</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">_context</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">TheStoredProcedureIsExecutedWithReader</span><span class="p">(</span><span class="s">"spFetchOrderById"</span><span class="p">,</span> 
                <span class="p">(</span><span class="s">"OrderId"</span><span class="p">,</span> <span class="m">23</span><span class="p">));</span> <span class="c1">// 7</span>

        <span class="n">Then</span><span class="p">.</span><span class="nf">UsingThe</span><span class="p">(</span><span class="n">_context</span><span class="p">)</span>
            <span class="p">.</span><span class="nf">TheReaderQueryResultsShouldContain</span><span class="p">(</span><span class="s">@"| Id | Product |
                                                  | -- | ------- |
                                                  | 23 | Apples  |"</span><span class="p">);</span> <span class="c1">// 8</span>

    <span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>

<p>Hopefully, the test is fairly self-explanatory :) but this is what’s going on:</p>

<ol>
  <li>the <code class="language-plaintext highlighter-rouge">LocalDbTestContext</code> constructor creates a temporary instance of localDb and creates a connection to it.</li>
  <li>the <code class="language-plaintext highlighter-rouge">DeployDacpac</code> method deploys DacPac containing the database schema we want to test.</li>
  <li><code class="language-plaintext highlighter-rouge">_context.RunTest(...)</code> this is where we define an Action delegate which is the actual test, making use of the supplied connection and transaction.</li>
  <li><code class="language-plaintext highlighter-rouge">var order = @"</code> here some setup data is defined using the markdown table syntax, this will be parsed into a <code class="language-plaintext highlighter-rouge">TabularData</code> object, see the <a href="#tabulardata">TabularData</a> section below, but you can populate data however you like.</li>
  <li><code class="language-plaintext highlighter-rouge">Given...TheFollowingSqlStatementIsExecuted()</code> here an arbitrary <code class="language-plaintext highlighter-rouge">SQL</code> command is executed, in this case removing a foreign key constraint so we only have to set up the data we specifically need for the test.</li>
  <li><code class="language-plaintext highlighter-rouge">TheFollowingDataExistsInTheTable()</code> this method takes the order <code class="language-plaintext highlighter-rouge">TabularData</code> we just defined and inserts it into the temporary database instance (inside the supplied transaction).</li>
  <li><code class="language-plaintext highlighter-rouge">When...TheStoredProcedureIsExecutedWithReader()</code> This method executes the named stored procedure that we are trying to test.</li>
  <li><code class="language-plaintext highlighter-rouge">Then...TheReaderQueryResultsShouldContain()</code> This method asserts that the result returned from the line above contains some data defined in a second tabular data string.</li>
  <li>After the test is complete its transaction is rolled back leaving the database context unpolluted for the next test.</li>
</ol>

<h2 id="leveraging-existing-work">Leveraging existing work</h2>

<p>The <code class="language-plaintext highlighter-rouge">LocalDbTestContext</code> class’s constructor is responsible for setting everything up ready for a set of tests to be executed. For managing the LocalDb instances, I am using the excellent <code class="language-plaintext highlighter-rouge">MartinCostello.SqlLocalDb</code> package which makes this task relatively trivial and can be found <a href="https://github.com/martincostello/sqllocaldb">here on GitHub</a> and <a href="https://www.nuget.org/packages/MartinCostello.SqlLocalDb/">here on Nuget</a></p>

<p>For the DacPac deployment, I took inspiration from <a href="https://stackoverflow.com/questions/43365451/improve-the-performance-of-dacpac-deployment-using-c-sharp">this StackOverflow thread</a>. The framework contains a class named <code class="language-plaintext highlighter-rouge">DacPacInfo</code> which is passed a string either containing a path to a dacpac file or a dacpac file name. If passed a path it will just use that path, otherwise it will traverse up the solution directory structure to a configurable number of levels and then use the file name to search for matching dacpac files and use the first onenit finds, this second method obviously takes longer.</p>

<h2 id="dbtestcontext-runtest-method">DbTestContext RunTest method</h2>

<p>The <code class="language-plaintext highlighter-rouge">RunTest()</code> method unsuprisingly runs a test defined in the  <code class="language-plaintext highlighter-rouge">Action&lt;IDbConnection, IDbTransaction&gt;</code> passed into the method.</p>

<p>A new connection is opened and a new <code class="language-plaintext highlighter-rouge">SqlTransaction</code> created which are passed to the Action. The Action is called within a <code class="language-plaintext highlighter-rouge">try finally</code> block, which is then used to tidy up any open <code class="language-plaintext highlighter-rouge">DataReader</code> objects on the connection and roll back the <code class="language-plaintext highlighter-rouge">SqlTransaction</code> after the test Action has been invoked, this ensures that each test starts with a clean slate unaffected by other tests.</p>

<p>There is also an overload of the <code class="language-plaintext highlighter-rouge">RunTest()</code> method which not begin and roll back a transaction, this is useful for testing repository classes which usually like to creat a new connection, use it and dispose it soon afterwards. Please not you will have to manage and tidying up of test data to ensure tests do not interfere with each other as theres no transaction to be rolled back for you.</p>

<h2 id="some-nice-extra-features">Some nice extra features</h2>

<h3 id="tabulardata">TabularData</h3>

<p>The <code class="language-plaintext highlighter-rouge">TabularData</code> class can be used for human-readable data definition.</p>

<p>We are used to defining tabular data in Markdown tables and also using Specflow’s example tables, data expressed in this format is far easier for a human to ‘parse’ than SQL statements. So, I created a class called <code class="language-plaintext highlighter-rouge">TabularData</code> which has methods for converting to and from markdown table strings and also converting to SQL statements, and from <code class="language-plaintext highlighter-rouge">SqlDataReader</code>, it also has methods for evaluating whether two <code class="language-plaintext highlighter-rouge">TabularData</code> are equal and whether one contains another. The code can be found <a href="https://github.com/andrewjpoole/CSharpSqlTests/blob/main/CSharpSqlTests/TabularData.cs">here</a>. Here are some examples of its use:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// Using markdown/specflow table style strings</span>
<span class="kt">var</span> <span class="n">testString</span> <span class="p">=</span> <span class="s">@" | id | state     | created    | ref          |
                    | -- | --------- | ---------- | ------------ |
                    | 1  | created   | 2021/11/02 | 23hgf4hj3gf4 |
                    | 2  | pending   | 2021/11/01 | 623kj4hv6hv4 |
                    | 3  | completed | 2021/10/31 | e0v9736eu476 |"</span><span class="p">;</span>

<span class="c1">// Using static builder methods (handy if the table has lots of columns)</span>
<span class="kt">var</span> <span class="n">tabularData</span> <span class="p">=</span> <span class="n">TabularData</span>
        <span class="p">.</span><span class="nf">CreateWithColumns</span><span class="p">(</span><span class="s">"column1"</span><span class="p">,</span> <span class="s">"column2"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AddRowWithValues</span><span class="p">(</span><span class="s">"valueA"</span><span class="p">,</span> <span class="s">"valueB"</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AddRowWithValues</span><span class="p">(</span><span class="s">"valueC"</span><span class="p">,</span> <span class="s">"valueD"</span><span class="p">);</span>
</code></pre></div></div>

<h4 id="string-value-interpretation">String value interpretation</h4>

<p>The following table shows how string values are interpreted in <code class="language-plaintext highlighter-rouge">TabularData</code>:</p>

<table>
  <thead>
    <tr>
      <th>String value</th>
      <th>Interpreted Value</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>2021-11-03</td>
      <td>a DateTime, use any parsable date and time string</td>
    </tr>
    <tr>
      <td>234</td>
      <td>an int</td>
    </tr>
    <tr>
      <td>null</td>
      <td>null</td>
    </tr>
    <tr>
      <td>emptyString</td>
      <td>an empty string</td>
    </tr>
    <tr>
      <td>true</td>
      <td>a boolean true</td>
    </tr>
    <tr>
      <td>false</td>
      <td>a boolean false</td>
    </tr>
    <tr>
      <td>“2”</td>
      <td>a string</td>
    </tr>
  </tbody>
</table>

<p>One thing to note, the <code class="language-plaintext highlighter-rouge">TabularData</code> class doesn’t know the schema of the database table it describes. So if you will be using one to populate a table, the column names and rows data types that you populate it with need to match the table schema otherwise a <code class="language-plaintext highlighter-rouge">SqlException</code> will be thrown when attempting to insert the data.</p>

<h3 id="given-when-and-then-helper-classes">Given, When and Then helper classes</h3>

<p>Recently I have started separating out the arrange, act and assert parts of a test into <code class="language-plaintext highlighter-rouge">Given</code>, <code class="language-plaintext highlighter-rouge">When</code> and <code class="language-plaintext highlighter-rouge">Then</code> classes, this gives a nice fluent interface and makes the tests nice and short which improves readability. The framework is un-opinionated about how you interact with the database, but these helper classes just use the <code class="language-plaintext highlighter-rouge">System.Data</code> namespace.</p>

<p>The <code class="language-plaintext highlighter-rouge">Given</code> class is responsible for the ‘arrange’ part of the test, it contains methods for inserting test data into a table using markdown table strings or an instance of a <code class="language-plaintext highlighter-rouge">TabularData</code>. It also contains methods for executing arbitrary SQL statements (e.g. to remove a foreign key constraint to reduce the amount of data seeding required) and</p>

<p>The <code class="language-plaintext highlighter-rouge">When</code> class is responsible for the ‘act’ part of the test and contains methods for executing Stored Procedures and various types of query, the results are stored on the shared instance of the <code class="language-plaintext highlighter-rouge">LocalDbTestContext</code> so that the <code class="language-plaintext highlighter-rouge">Then</code> class can neatly access them for assertions, but there are also overloads which return the result an Out argument.</p>

<p>The <code class="language-plaintext highlighter-rouge">Then</code> class is responsible for the ‘assert’ part of the test and contains methods for asserting that query results are equal to or contain data specified using markdown table strings or an instance of a <code class="language-plaintext highlighter-rouge">TabularData</code> passed in as an argument. It also has methods for executing either scaler or reader queries in case you need to assert against data in the database changed by a stored procedure under test.</p>

<p>All three share the instance of the <code class="language-plaintext highlighter-rouge">IDbTestContext</code>, which allows them to access its <code class="language-plaintext highlighter-rouge">State</code> dictionary, its <code class="language-plaintext highlighter-rouge">CurrentDataReader</code> and its <code class="language-plaintext highlighter-rouge">LastNonReaderQueryResult</code> objects which contain the results of DataReader and non-DataReader queries against the database.</p>

<p>The shared <code class="language-plaintext highlighter-rouge">IDbTestContext</code> in these classes is public so you can extend them using extension methods, there is an example of this below.</p>

<p>Here is some of the code for the <code class="language-plaintext highlighter-rouge">Given</code> class showing the use of <code class="language-plaintext highlighter-rouge">System.Data</code> types to utilise the connection:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Given</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">ILocalDbTestContext</span> <span class="n">Context</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Given</span><span class="p">(</span><span class="n">ILocalDbTestContext</span> <span class="n">context</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Context</span> <span class="p">=</span> <span class="n">context</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">Given</span> <span class="nf">UsingThe</span><span class="p">(</span><span class="n">LocalDbTestContext</span> <span class="n">context</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">logAction</span><span class="p">);</span>

    <span class="k">public</span> <span class="n">Given</span> <span class="n">And</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span> <span class="c1">// pointless syntactic sugar to make the tests read nicely</span>
    
    <span class="k">public</span> <span class="n">Given</span> <span class="nf">TheDacpacIsDeployed</span><span class="p">(</span><span class="kt">string</span> <span class="n">dacpacProjectName</span> <span class="p">=</span> <span class="s">""</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Context</span><span class="p">.</span><span class="nf">DeployDacpac</span><span class="p">(</span><span class="n">dacpacProjectName</span><span class="p">);</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Given</span> <span class="nf">TheFollowingDataExistsInTheTable</span><span class="p">(</span><span class="kt">string</span> <span class="n">tableName</span><span class="p">,</span> <span class="kt">string</span> <span class="n">markdownTableString</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">tabularData</span> <span class="p">=</span> <span class="n">TabularData</span><span class="p">.</span><span class="nf">FromMarkdownTableString</span><span class="p">(</span><span class="n">markdownTableString</span><span class="p">);</span>
        <span class="k">return</span> <span class="nf">TheFollowingDataExistsInTheTable</span><span class="p">(</span><span class="n">tableName</span><span class="p">,</span> <span class="n">tabularData</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Given</span> <span class="nf">TheFollowingDataExistsInTheTable</span><span class="p">(</span><span class="kt">string</span> <span class="n">tableName</span><span class="p">,</span> <span class="n">TabularData</span> <span class="n">tabularData</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">try</span>
        <span class="p">{</span>
            <span class="kt">var</span> <span class="n">cmd</span> <span class="p">=</span> <span class="n">Context</span><span class="p">.</span><span class="n">SqlConnection</span><span class="p">.</span><span class="nf">CreateCommand</span><span class="p">();</span>
            <span class="n">cmd</span><span class="p">.</span><span class="n">CommandText</span> <span class="p">=</span> <span class="n">tabularData</span><span class="p">.</span><span class="nf">ToSqlString</span><span class="p">(</span><span class="n">tableName</span><span class="p">);</span>
            <span class="n">cmd</span><span class="p">.</span><span class="n">CommandType</span> <span class="p">=</span> <span class="n">CommandType</span><span class="p">.</span><span class="n">Text</span><span class="p">;</span>
            <span class="n">cmd</span><span class="p">.</span><span class="n">Transaction</span> <span class="p">=</span> <span class="n">Context</span><span class="p">.</span><span class="n">SqlTransaction</span><span class="p">;</span>

            <span class="n">Context</span><span class="p">.</span><span class="n">LastQueryResult</span> <span class="p">=</span> <span class="n">cmd</span><span class="p">.</span><span class="nf">ExecuteNonQuery</span><span class="p">();</span>

            <span class="nf">LogMessage</span><span class="p">(</span><span class="s">"TheFollowingDataExistsInTheTable executed successfully"</span><span class="p">);</span>

            <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
        <span class="p">}</span>
        <span class="k">catch</span> <span class="p">(</span><span class="n">Exception</span> <span class="n">ex</span><span class="p">)</span>
        <span class="p">{</span>
            <span class="nf">LogMessage</span><span class="p">(</span><span class="s">$"Exception thrown while executing TheFollowingDataExistsInTheTable, </span><span class="p">{</span><span class="n">ex</span><span class="p">}</span><span class="s">"</span><span class="p">);</span>
            <span class="k">throw</span><span class="p">;</span>
        <span class="p">}</span>
    <span class="p">}</span>
    <span class="c1">// some methods and the triple slash documentation is removed for brevity    </span>
<span class="p">}</span>
</code></pre></div></div>

<p>To extend <code class="language-plaintext highlighter-rouge">Given</code> to add more methods use extension methods:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">static</span> <span class="k">class</span> <span class="nc">GivenExtensions</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="k">static</span> <span class="n">Given</span> <span class="nf">SomeOtherSetupOperationIsPerformed</span><span class="p">(</span><span class="k">this</span> <span class="n">Given</span> <span class="n">given</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="c1">// do something here</span>
        <span class="c1">// e.g. access the shared Context </span>
        <span class="c1">// across the Given, When and Then</span>
        <span class="n">given</span><span class="p">.</span><span class="n">Context</span><span class="p">.</span><span class="n">State</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="s">"newStateObject"</span><span class="p">,</span> <span class="m">87654</span><span class="p">)</span> 

        <span class="c1">// returning this enables the fluent method chaining.</span>
        <span class="k">return</span> <span class="n">given</span><span class="p">;</span> 
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="performance-and-efficiency">Performance and efficiency</h2>

<p>Starting a temporary localDb and deploying a DacPac are both quite expensive tasks, so it is best to do these jobs once for a set of tests, various test frameworks achieve this in different ways, in xUnit it is the <code class="language-plaintext highlighter-rouge">IClassFixture&lt;T&gt;</code>. A test class that implements this interface will have an instance of <code class="language-plaintext highlighter-rouge">T</code> injected into its constructor and the <code class="language-plaintext highlighter-rouge">T</code> will be disposed after any tests have been run.</p>

<p>Here is the class that I am injecting using <code class="language-plaintext highlighter-rouge">IClassFixture</code> which creates the localDb instance and deploys the DacPac.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">LocalDbContextFixture</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">LocalDbTestContext</span> <span class="n">Context</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">LocalDbContextFixture</span><span class="p">(</span><span class="n">IMessageSink</span> <span class="n">sink</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Context</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">LocalDbTestContext</span><span class="p">(</span><span class="s">"SampleDb"</span><span class="p">,</span> <span class="n">log</span> <span class="p">=&gt;</span> <span class="n">sink</span><span class="p">.</span><span class="nf">OnMessage</span><span class="p">(</span><span class="k">new</span> <span class="nf">DiagnosticMessage</span><span class="p">(</span><span class="n">log</span><span class="p">)));</span>
        <span class="n">Context</span><span class="p">.</span><span class="nf">DeployDacpac</span><span class="p">();</span> <span class="c1">// If the DacPac name != database name, pass the DacPac name in here, or even better an absolute path to the file.</span>
    <span class="p">}</span>       

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">Context</span><span class="p">.</span><span class="nf">TearDown</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>In my simple test scenario, the localDb takes around 10 seconds to spin up and the DacPac takes another 10 seconds, but this is roughly comparable to the setup time that an equivalent tSQLt test would take.</p>

<h3 id="modes">Modes</h3>

<p>The framework has the following modes:</p>

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Explanation</th>
      <th>Use-case</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">TemporaryLocalDbInstance</code></td>
      <td>The framework spins up a temporary localDb instance and tears it down again afterwards</td>
      <td>Great for local development</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ExistingLocalDbInstanceViaInstanceName</code></td>
      <td>The framework will locate and use a named pre-existing localDb instance</td>
      <td>Can be useful in some CI scenarios, especially where the context is monitored e.g. by SqlCover</td>
    </tr>
    <tr>
      <td><code class="language-plaintext highlighter-rouge">ExistingDatabaseViaConnectionString</code></td>
      <td>The framework will connect to a SQL Server instance using the supplied connection string</td>
      <td>Can be useful in some CI scenarios, especially where the context is monitored e.g. by SqlCover or where SQL is hosted in a container</td>
    </tr>
  </tbody>
</table>

<p>The mode is set in the constructor of the <code class="language-plaintext highlighter-rouge">DbTestContext</code> but it can also be overridden using environment variables:</p>

<table>
  <thead>
    <tr>
      <th>Environment Variable Name</th>
      <th>Purpose</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>“CSharpSqlTests_Mode”</td>
      <td>Set the mode</td>
    </tr>
    <tr>
      <td>“CSharpSqlTests_ConnectionString”</td>
      <td>Specify a connection string to a SQL Server instance</td>
    </tr>
    <tr>
      <td>“CSharpSqlTests_ExistingLocalDbInstanceName”</td>
      <td>Specify the name of an existing LocalDB instance to use</td>
    </tr>
  </tbody>
</table>

<p>This means your code can use <code class="language-plaintext highlighter-rouge">TemporaryLocalDbInstance</code> by default for local dev but your CI build can switch to a different mode using environment variables.</p>

<h3 id="sqlcover">SQLCover</h3>

<p>If you would also like to measure code coverage of your SQL code, there is a great tool named <a href="https://github.com/GoEddie/SQLCover">SqlCover</a> which you can read about in Ed Courage’s post <a href="https://www.clear.bank/newsroom/automate-sql-testing-using-azure-devops-and-sqlcover">Automate SQL Testing using Azure DevOps and SQLCover</a>. If you follow the method in Ed’s post, you would deploy the DacPac during the setup of the SQL container and then use the <code class="language-plaintext highlighter-rouge">ExistingDatabaseViaConnectionString</code> and supply the <code class="language-plaintext highlighter-rouge">DbTestContext</code> with the connection string to the SQL server in the container. At ClearBank we have a yaml template which takes care of this part for us.</p>

<h2 id="in-closing">In closing</h2>

<p>All of the source code can be found on GitHub <a href="https://github.com/andrewjpoole/CSharpSqlTests">here</a>
Contributions are very welcome.</p>

<p>So that’s it, a lightweight framework that sets up your db instance and then hopefully gets out of the way, letting you test your db objects and repository classes however you like but also providing a few helpful classes for common tasks. Hope you find it useful and thanks for reading!</p>

<p>Packages are available on Nuget, the main <a href="https://www.nuget.org/packages/CSharpSqlTests/">CSharpSqlTests package here</a>, additional <a href="https://www.nuget.org/packages/CSharpSqlTests.Xunit/">Xunit extensions package here</a> and additional <a href="https://www.nuget.org/packages/CSharpSqlTests.NUnit/">NUnit extensions package here</a></p>]]></content><author><name>Andrew Poole</name></author><summary type="html"><![CDATA[TL/DR You know you should be testing T-SQL code in stored procedures/views and if you’re underwhelmed by the T-Sql based frameworks available you might like to use a nice fluent C# framework and even use markdown table syntax to define data! If so, read on…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/csharpsqltests.jpg" /><media:content medium="image" url="https://www.forkinthecode.net/images/csharpsqltests.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Testing Service Bus Handlers using Azure.Messaging.ServiceBus client library</title><link href="https://www.forkinthecode.net/2021/12/17/testing-message-handlers-using-azure-messaging-servicebus.html" rel="alternate" type="text/html" title="Testing Service Bus Handlers using Azure.Messaging.ServiceBus client library" /><published>2021-12-17T00:00:00+00:00</published><updated>2021-12-17T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2021/12/17/testing-message-handlers-using-azure-messaging-servicebus</id><content type="html" xml:base="https://www.forkinthecode.net/2021/12/17/testing-message-handlers-using-azure-messaging-servicebus.html"><![CDATA[<p>TL/DR - At ClearBank we love testing and the new <code class="language-plaintext highlighter-rouge">Azure.Messaging.ServiceBus</code> package makes testing Service Bus handlers easy at last! Check out how we did it.</p>

<h2 id="background">Background</h2>

<p>In April 2020 Microsoft brought out a new client library for Azure Service Bus called <code class="language-plaintext highlighter-rouge">Azure.Messaging.ServiceBus</code>, this new library is based on the open Advanced Message Queuing Protocol (AMQP) standard. Microsoft outlines:</p>
<blockquote>
  <p><a href="https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-amqp-overview">AMQP enables you to build cross-platform, hybrid applications using a vendor-neutral and implementation-neutral, open standard protocol. You can construct applications using components that are built using different languages and frameworks, and that run on different operating systems. All these components can connect to Service Bus and seamlessly exchange structured business messages efficiently and at full fidelity.</a></p>
</blockquote>

<p>The class library documentation hints at this library being testable! This is great because one of the frustrations of using previous Service Bus client libraries was that absolutely everything was sealed or protected, meaning the only way to test client code was to wrap up and abstract away the service bus infrastructure. The situation might have been helped by a local emulator, but despite being a highly requested and up-voted feature request, an emulator was never officially implemented. So any improvements to the testability of Service Bus client code would be very welcome indeed!</p>

<p>The test support here is basically a few classes which are public and not sealed, a sprinkling of overridable methods and a factory class for creating models.</p>

<p>There are no official samples yet and very few (if any) blog posts covering how to test, but after a bit of trial and error we managed to get some tests working that we are quite pleased with, hence sharing here so that others might also benefit. This article covers testing the very basic handling of messages, although it should also be a useful starting point for testing more advanced features.</p>

<h2 id="component-tests">Component tests</h2>

<p>At ClearBank we are favouring ‘component tests’ over reams of unit tests, I’m not sure who coined the name ‘component test’, but I see them as a kind of internal integration test. So we run some kind of test host, using real concrete objects, with the exception of anything which touches the network, these objects are mocked. We test as much of the service as possible i.e. including the <code class="language-plaintext highlighter-rouge">Startup</code> class and the <code class="language-plaintext highlighter-rouge">Program</code> class if possible. The tests include happy and sad paths, enough to give sufficiently high line and branch coverage of the tested services. These kind of tests take longer to setup than pure unit tests making Test Driven Development (TDD) a bit harder to start with, but they run locally, they run much faster and are less brittle than integration/end-to-end tests, giving the same confidence that the business logic is proven in a smaller number of tests than traditional unit tests. Of course, you still need a couple of integration tests but these need only prove that the integration is working, rather than all of the paths through the logic.</p>

<h2 id="testing-message-handlers">Testing message handlers</h2>

<p>The main requirement when testing a service bus message handler is to be able to create a <code class="language-plaintext highlighter-rouge">ServiceBusReceivedMessage</code>. This class doesn’t have a public constructor, but there is <code class="language-plaintext highlighter-rouge">ServiceBusModelFactory</code> class with a <code class="language-plaintext highlighter-rouge">ServiceBusReceivedMessage()</code> method especially for the purpose! This needs to be at the heart of our test approach.</p>

<p>When we create the artificial <code class="language-plaintext highlighter-rouge">ServiceBusReceivedMessage</code> it needs to be packaged up in a <code class="language-plaintext highlighter-rouge">ProcessMessageEventArgs</code> however, if we want to spy on what happens to the message, we can inherit from this class and override <code class="language-plaintext highlighter-rouge">CompleteMessageAsync</code>, <code class="language-plaintext highlighter-rouge">DeadLetterMessageAsync</code> and <code class="language-plaintext highlighter-rouge">AbandonMessageAsync</code> methods and set flags accordingly. We called this class <code class="language-plaintext highlighter-rouge">TestableProcessMessageEventArgs</code>.</p>

<h3 id="here-is-our-testableprocessmessageeventargs-class">Here is our <code class="language-plaintext highlighter-rouge">TestableProcessMessageEventArgs</code> class</h3>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">TestableProcessMessageEventArgs</span> <span class="p">:</span> <span class="n">ProcessMessageEventArgs</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">WasCompleted</span><span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="kt">bool</span> <span class="n">WasDeadLettered</span><span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="k">private</span> <span class="k">set</span><span class="p">;</span> <span class="p">}</span>
    <span class="k">public</span> <span class="n">DateTime</span> <span class="n">Created</span><span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span>

    <span class="k">public</span> <span class="nf">TestableProcessMessageEventArgs</span><span class="p">(</span><span class="n">ServiceBusReceivedMessage</span> <span class="n">message</span><span class="p">)</span> <span class="p">:</span> <span class="k">base</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="k">null</span><span class="p">,</span> <span class="n">CancellationToken</span><span class="p">.</span><span class="n">None</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">Created</span> <span class="p">=</span> <span class="n">DateTime</span><span class="p">.</span><span class="n">Now</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">CompleteMessageAsync</span><span class="p">(</span><span class="n">ServiceBusReceivedMessage</span> <span class="n">message</span><span class="p">,</span>
        <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationToken</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="n">WasCompleted</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">DeadLetterMessageAsync</span><span class="p">(</span><span class="n">ServiceBusReceivedMessage</span> <span class="n">message</span><span class="p">,</span> <span class="kt">string</span> <span class="n">deadLetterReason</span><span class="p">,</span>
        <span class="kt">string</span> <span class="n">deadLetterErrorDescription</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span> <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">new</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="n">WasDeadLettered</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>
        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="n">Task</span> <span class="nf">AbandonMessageAsync</span><span class="p">(</span><span class="n">ServiceBusReceivedMessage</span> <span class="n">message</span><span class="p">,</span> <span class="n">IDictionary</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object</span><span class="p">&gt;</span> <span class="n">propertiesToModify</span> <span class="p">=</span> <span class="k">null</span><span class="p">,</span>
        <span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">CancellationToken</span><span class="p">())</span>
    <span class="p">{</span>
        <span class="k">return</span> <span class="n">Task</span><span class="p">.</span><span class="n">CompletedTask</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>The next thing we need to mock is the <code class="language-plaintext highlighter-rouge">ServiceBusProcessor</code> class, this is returned by the <code class="language-plaintext highlighter-rouge">ServiceBusClient</code> and communicates with the service bus, passing messages to the handler for a specific queue or topic. We could try to use Moq but its easier to inherit from <code class="language-plaintext highlighter-rouge">ServiceBusProcessor</code> and override its <code class="language-plaintext highlighter-rouge">StartProcessingAsync()</code> method, this stops it from realising that it isn’t connected to a real service bus. We called this class <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code>.</p>

<p>We can then call <code class="language-plaintext highlighter-rouge">base.OnProcessMessageAsync(args)</code> on the <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code> passing in a an artificial message created using the 
<code class="language-plaintext highlighter-rouge">ServiceBusModelFactory.ServiceBusReceivedMessage()</code> mentioned above. This will present the artificial message to the handler, as if it were connected to a real service bus receiving a real message.</p>

<p>We can add a couple of helpful features to the <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code> such as a collection of <code class="language-plaintext highlighter-rouge">TestableProcessMessageEventArgs</code> called <code class="language-plaintext highlighter-rouge">MessageDeliveryAttempts</code> to assert against and a generic method for sending messages, we can also simulate retries in order to test sad paths and/or exponential back off policies etc.</p>

<h3 id="here-is-our-testableservicebusprocessor-class">Here is our <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code> class</h3>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">TestableServiceBusProcessor</span> <span class="p">:</span> <span class="n">ServiceBusProcessor</span>
<span class="p">{</span>
    <span class="k">public</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">TestableProcessMessageEventArgs</span><span class="p">&gt;</span> <span class="n">MessageDeliveryAttempts</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="n">SendMessageWithRetries</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">payload</span><span class="p">,</span> <span class="kt">int</span> <span class="n">maxDeliveryCount</span> <span class="p">=</span> <span class="m">5</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">attempt</span> <span class="p">=</span> <span class="m">1</span><span class="p">;</span> <span class="n">attempt</span> <span class="p">&lt;=</span> <span class="n">maxDeliveryCount</span><span class="p">;</span> <span class="n">attempt</span><span class="p">++)</span>
        <span class="p">{</span>
            <span class="c1">// Don't send retry if the message was sent already and completed</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Any</span><span class="p">()</span> <span class="p">&amp;&amp;</span> <span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Last</span><span class="p">().</span><span class="n">WasCompleted</span><span class="p">)</span>
                <span class="k">return</span><span class="p">;</span>

            <span class="k">await</span> <span class="nf">SendMessage</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">attempt</span><span class="p">);</span>

            <span class="c1">// Simulate the message being deadlettered if max delivery count is hit</span>
            <span class="k">if</span> <span class="p">(</span><span class="n">attempt</span> <span class="p">==</span> <span class="n">maxDeliveryCount</span><span class="p">)</span>
                <span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Last</span><span class="p">().</span><span class="n">WasDeadLettered</span> <span class="p">=</span> <span class="k">true</span><span class="p">;</span>

        <span class="p">}</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span> <span class="n">SendMessage</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">payload</span><span class="p">,</span> <span class="kt">int</span> <span class="n">attempt</span> <span class="p">=</span> <span class="m">1</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">args</span> <span class="p">=</span> <span class="nf">CreateMessageArgs</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">attempt</span><span class="p">);</span>
        <span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Add</span><span class="p">((</span><span class="n">TestableProcessMessageEventArgs</span><span class="p">)</span><span class="n">args</span><span class="p">);</span>
        <span class="k">await</span> <span class="k">base</span><span class="p">.</span><span class="nf">OnProcessMessageAsync</span><span class="p">(</span><span class="n">args</span><span class="p">);</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">ProcessMessageEventArgs</span> <span class="n">CreateMessageArgs</span><span class="p">&lt;</span><span class="n">T</span><span class="p">&gt;(</span><span class="n">T</span> <span class="n">payload</span><span class="p">,</span> <span class="kt">int</span> <span class="n">deliveryCount</span> <span class="p">=</span> <span class="m">1</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">payloadJson</span> <span class="p">=</span> <span class="n">JsonSerializer</span><span class="p">.</span><span class="nf">Serialize</span><span class="p">(</span><span class="n">payload</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">message</span> <span class="p">=</span> <span class="n">ServiceBusModelFactory</span><span class="p">.</span><span class="nf">ServiceBusReceivedMessage</span><span class="p">(</span>
            <span class="n">body</span><span class="p">:</span> <span class="n">BinaryData</span><span class="p">.</span><span class="nf">FromString</span><span class="p">(</span><span class="n">payloadJson</span><span class="p">),</span>
            <span class="n">deliveryCount</span><span class="p">:</span> <span class="n">deliveryCount</span><span class="p">);</span>

        <span class="kt">var</span> <span class="n">args</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TestableProcessMessageEventArgs</span><span class="p">(</span><span class="n">message</span><span class="p">);</span>

        <span class="k">return</span> <span class="n">args</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">override</span> <span class="k">async</span> <span class="n">Task</span> <span class="nf">StartProcessingAsync</span><span class="p">(</span><span class="n">CancellationToken</span> <span class="n">cancellationToken</span> <span class="p">=</span> <span class="k">default</span><span class="p">)</span>
    <span class="p">{</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="how-to-use-them">How to use them</h2>

<p>So, to use these classes in a component test, we can use the excellent <code class="language-plaintext highlighter-rouge">TestHost</code> from the <code class="language-plaintext highlighter-rouge">Microsoft.AspNetCore.TestHost</code> package, this enables us to run a service in memory, calling the <code class="language-plaintext highlighter-rouge">ConfigureServices</code> method as normal, but then overriding some of the configurations i.e. the ones that touch the network that we need to mock. Consider the following code:</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">TestHost</span> <span class="p">:</span> <span class="n">IDisposable</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">IHost</span> <span class="n">_server</span><span class="p">;</span>
    <span class="k">public</span> <span class="n">Mock</span><span class="p">&lt;</span><span class="n">ServiceBusSender</span><span class="p">&gt;</span> <span class="n">MockTestQueue2Sender</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="k">public</span> <span class="n">TestableServiceBusProcessor</span> <span class="n">TestableQueue1MessageProcessor</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="k">public</span> <span class="n">Mock</span><span class="p">&lt;</span><span class="n">IWidget</span><span class="p">&gt;</span> <span class="n">MockWidgetService</span> <span class="p">{</span> <span class="k">get</span><span class="p">;</span> <span class="p">}</span> <span class="p">=</span> <span class="k">new</span><span class="p">();</span>
    <span class="k">public</span> <span class="n">IServiceProvider</span> <span class="n">Services</span> <span class="p">=&gt;</span> <span class="n">_server</span><span class="p">.</span><span class="n">Services</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">NumberOfSimulatedServiceBusMessageRetries</span> <span class="p">=</span> <span class="m">5</span><span class="p">;</span>
    <span class="k">public</span> <span class="kt">int</span> <span class="n">InitialRetryDelayForServiceBusMessageRetriesInMs</span> <span class="p">=</span> <span class="m">100</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">TestHost</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">builder</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">HostBuilder</span><span class="p">()</span>
            <span class="p">.</span><span class="nf">ConfigureWebHost</span><span class="p">(</span><span class="n">webHost</span> <span class="p">=&gt;</span>
            <span class="p">{</span>
                <span class="n">webHost</span><span class="p">.</span><span class="nf">UseTestServer</span><span class="p">()</span>
                    <span class="p">.</span><span class="nf">ConfigureServices</span><span class="p">((</span><span class="n">context</span><span class="p">,</span> <span class="n">services</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="n">Program</span><span class="p">.</span><span class="nf">ConfigureHost</span><span class="p">(</span><span class="n">services</span><span class="p">,</span> <span class="n">context</span><span class="p">.</span><span class="n">Configuration</span><span class="p">))</span>
                    <span class="p">.</span><span class="nf">ConfigureTestServices</span><span class="p">((</span><span class="n">services</span><span class="p">)</span> <span class="p">=&gt;</span>
                    <span class="p">{</span>
                        <span class="kt">var</span> <span class="n">client</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Mock</span><span class="p">&lt;</span><span class="n">ServiceBusClient</span><span class="p">&gt;();</span>

                        <span class="n">client</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="nf">CreateSender</span><span class="p">(</span><span class="n">It</span><span class="p">.</span><span class="n">Is</span> <span class="p">&lt;</span> <span class="kt">string</span> <span class="p">&gt;</span> <span class="p">(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span> <span class="p">==</span> <span class="s">"testQueue2"</span><span class="p">)))</span>
                            <span class="p">.</span><span class="nf">Returns</span><span class="p">(</span><span class="n">MockTestQueue2Sender</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span>

                        <span class="n">client</span><span class="p">.</span><span class="nf">Setup</span><span class="p">(</span><span class="n">t</span> <span class="p">=&gt;</span> <span class="n">t</span><span class="p">.</span><span class="nf">CreateProcessor</span><span class="p">(</span><span class="n">It</span><span class="p">.</span><span class="n">Is</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;(</span><span class="n">s</span> <span class="p">=&gt;</span> <span class="n">s</span> <span class="p">==</span> <span class="s">$"testQueue1"</span><span class="p">)))</span>
                            <span class="p">.</span><span class="nf">Returns</span><span class="p">(</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">);</span>

                        <span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">client</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span>

                        <span class="c1">// register other test services here...</span>
                        <span class="n">services</span><span class="p">.</span><span class="nf">AddSingleton</span><span class="p">(</span><span class="n">MockWidgetService</span><span class="p">.</span><span class="n">Object</span><span class="p">);</span>

                    <span class="p">}).</span><span class="nf">Configure</span><span class="p">(</span><span class="n">app</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="p">});</span>
            <span class="p">});</span>

        <span class="n">_server</span> <span class="p">=</span> <span class="n">builder</span><span class="p">.</span><span class="nf">Build</span><span class="p">();</span>
        <span class="n">_server</span><span class="p">.</span><span class="nf">StartAsync</span><span class="p">();</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">void</span> <span class="nf">Dispose</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_server</span><span class="p">?.</span><span class="nf">StopAsync</span><span class="p">().</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
        <span class="n">_server</span><span class="p">?.</span><span class="nf">Dispose</span><span class="p">();</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>So we’re using Moq to create a Mock <code class="language-plaintext highlighter-rouge">ServiceBusClient</code>, this will be registered into the DI container and when it’s <code class="language-plaintext highlighter-rouge">CreateProcessor()</code> method is called with the correct queue name, an instance of our <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code> will be returned. We are also setting up a Mock <code class="language-plaintext highlighter-rouge">ServiceBusSender</code> which we can use later to Assert whether messages were sent to a different queue.
Finally we have a Mock <code class="language-plaintext highlighter-rouge">IWidget</code> service, which our message handler calls and we can use to throw exceptions or simulate processing delays etc.</p>

<p><img src="/images//testing_azure_service_bus_message_handlers_using_azure_messaging_servicebus_image1.png" alt="Sequence diagram" /></p>

<h2 id="the-actual-tests">The actual tests</h2>

<p>The following code shows the actual tests, we decided to split the setup, execution and assertion into a set of helpers named <code class="language-plaintext highlighter-rouge">Given</code>, <code class="language-plaintext highlighter-rouge">When</code> and <code class="language-plaintext highlighter-rouge">Then</code>, this allows for a nice fluent interface for the tests and makes them nice and readable.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">a_message_sent_to_the_queue_is_handled_and_completed</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="nn">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TestHost</span><span class="p">();</span>

    <span class="n">Given</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ATestPayloadIsGenerated</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">testPayload</span><span class="p">);</span>

    <span class="n">When</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AMessageIsSentToTestQueue1</span><span class="p">(</span><span class="n">testPayload</span><span class="p">);</span>

    <span class="n">Then</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">TheWidgetServiceWasCalled</span><span class="p">(</span><span class="n">times</span><span class="p">:</span> <span class="m">1</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">AMessageWasSentToTestQueue2</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheMessageWasCompleted</span><span class="p">();</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">a_message_sent_to_the_queue_is_handled_and_when_permanentException_is_thrown_is_dead_lettered</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="nn">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TestHost</span><span class="p">();</span>

    <span class="n">Given</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ATestPayloadIsGenerated</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">testPayload</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheWidgetWillThrowAPermanentException</span><span class="p">();</span>

    <span class="n">When</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AMessageIsSentToTestQueue1</span><span class="p">(</span><span class="n">testPayload</span><span class="p">);</span>

    <span class="n">Then</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AMessageWasSentToTestQueue2</span><span class="p">(</span><span class="n">times</span><span class="p">:</span> <span class="m">0</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheMessageWasDeadLettered</span><span class="p">();</span>
<span class="p">}</span>

<span class="p">[</span><span class="n">Fact</span><span class="p">]</span>
<span class="k">public</span> <span class="k">void</span> <span class="nf">a_message_sent_to_the_queue_is_handled_and_when_transientException_is_thrown_is_retried_and_is_eventually_completed</span><span class="p">()</span>
<span class="p">{</span>
    <span class="k">using</span> <span class="nn">var</span> <span class="n">host</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TestHost</span><span class="p">();</span>

    <span class="n">Given</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">ATestPayloadIsGenerated</span><span class="p">(</span><span class="k">out</span> <span class="kt">var</span> <span class="n">testPayload</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheWidgetWillThrowANumberOfTransientExceptions</span><span class="p">(</span><span class="n">times</span><span class="p">:</span><span class="m">3</span><span class="p">);</span>

    <span class="n">When</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">AMessageIsSentToTestQueue1</span><span class="p">(</span><span class="n">testPayload</span><span class="p">,</span> <span class="n">simulateRetries</span><span class="p">:</span> <span class="k">true</span><span class="p">);</span>

    <span class="n">Then</span><span class="p">.</span><span class="nf">OnThe</span><span class="p">(</span><span class="n">host</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">TheMessageWasRetried</span><span class="p">(</span><span class="n">times</span><span class="p">:</span><span class="m">4</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheWidgetServiceWasCalled</span><span class="p">(</span><span class="n">times</span><span class="p">:</span><span class="m">4</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheRetriedMessagesHadIncreasingDelays</span><span class="p">()</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">AMessageWasSentToTestQueue2</span><span class="p">(</span><span class="n">times</span><span class="p">:</span><span class="m">1</span><span class="p">)</span>
        <span class="p">.</span><span class="nf">And</span><span class="p">().</span><span class="nf">TheMessageWasCompleted</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>

<h2 id="given-when-and-then-test-helpers">Given, When and Then test helpers</h2>

<p>Here is the code for the <code class="language-plaintext highlighter-rouge">When</code> class which simulates the message appearing on the queue</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">When</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TestHost</span> <span class="n">_host</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">When</span><span class="p">(</span><span class="n">TestHost</span> <span class="n">host</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_host</span> <span class="p">=</span> <span class="n">host</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">When</span> <span class="nf">OnThe</span><span class="p">(</span><span class="n">TestHost</span> <span class="n">host</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">host</span><span class="p">);</span>
    <span class="k">public</span> <span class="n">When</span> <span class="nf">And</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span>

    <span class="k">public</span> <span class="n">When</span> <span class="nf">AMessageIsSentToTestQueue1</span><span class="p">(</span><span class="kt">string</span> <span class="n">testPayload</span><span class="p">,</span> <span class="kt">bool</span> <span class="n">simulateRetries</span> <span class="p">=</span> <span class="k">false</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">payload</span> <span class="p">=</span> <span class="k">new</span> <span class="nf">TestQueueMessage</span><span class="p">(</span><span class="n">testPayload</span><span class="p">);</span>

        <span class="k">if</span> <span class="p">(</span><span class="n">simulateRetries</span><span class="p">)</span>
            <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="nf">SendMessageWithRetries</span><span class="p">(</span><span class="n">payload</span><span class="p">,</span> <span class="n">_host</span><span class="p">.</span><span class="n">NumberOfSimulatedServiceBusMessageRetries</span><span class="p">).</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>
        <span class="k">else</span>
            <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="nf">SendMessage</span><span class="p">(</span><span class="n">payload</span><span class="p">).</span><span class="nf">GetAwaiter</span><span class="p">().</span><span class="nf">GetResult</span><span class="p">();</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>And here is the code for the <code class="language-plaintext highlighter-rouge">Then</code> class which demonstrates how to use the <code class="language-plaintext highlighter-rouge">TestableServiceBusProcessor</code> and its collection of <code class="language-plaintext highlighter-rouge">MessageDeliveryAttempts</code>, each of which contains a <code class="language-plaintext highlighter-rouge">TestableProcessMessageEventArgs</code> that be can used to make assertions. We are using the <code class="language-plaintext highlighter-rouge">FluentAssertions</code> package.</p>

<div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">public</span> <span class="k">class</span> <span class="nc">Then</span>
<span class="p">{</span>
    <span class="k">private</span> <span class="k">readonly</span> <span class="n">TestHost</span> <span class="n">_host</span><span class="p">;</span>

    <span class="k">public</span> <span class="nf">Then</span><span class="p">(</span><span class="n">TestHost</span> <span class="n">host</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_host</span> <span class="p">=</span> <span class="n">host</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="k">static</span> <span class="n">Then</span> <span class="nf">OnThe</span><span class="p">(</span><span class="n">TestHost</span> <span class="n">host</span><span class="p">)</span> <span class="p">=&gt;</span> <span class="k">new</span><span class="p">(</span><span class="n">host</span><span class="p">);</span>
    <span class="k">public</span> <span class="n">Then</span> <span class="nf">And</span><span class="p">()</span> <span class="p">=&gt;</span> <span class="k">this</span><span class="p">;</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheMessageWasCompleted</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Last</span><span class="p">().</span><span class="n">WasCompleted</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">BeTrue</span><span class="p">();</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheMessageWasDeadLettered</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="nf">Last</span><span class="p">().</span><span class="n">WasDeadLettered</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">BeTrue</span><span class="p">();</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheMessageWasRetried</span><span class="p">(</span><span class="kt">int</span> <span class="n">times</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="n">Count</span><span class="p">.</span><span class="nf">Should</span><span class="p">().</span><span class="nf">Be</span><span class="p">(</span><span class="n">times</span><span class="p">);</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheWidgetServiceWasCalled</span><span class="p">(</span><span class="kt">int</span> <span class="n">times</span><span class="p">)</span> 
    <span class="p">{</span>
        <span class="n">_host</span><span class="p">.</span><span class="n">MockWidgetService</span><span class="p">.</span><span class="nf">Verify</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="nf">DoSomething</span><span class="p">(</span><span class="n">It</span><span class="p">.</span><span class="n">IsAny</span><span class="p">&lt;</span><span class="kt">string</span><span class="p">&gt;()),</span> <span class="n">Times</span><span class="p">.</span><span class="nf">Exactly</span><span class="p">(</span><span class="n">times</span><span class="p">));</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">AMessageWasSentToTestQueue2</span><span class="p">(</span><span class="kt">int</span> <span class="n">times</span> <span class="p">=</span> <span class="m">1</span><span class="p">)</span>
    <span class="p">{</span>
        <span class="n">_host</span><span class="p">.</span><span class="n">MockTestQueue2Sender</span><span class="p">.</span><span class="nf">Verify</span><span class="p">(</span><span class="n">x</span> <span class="p">=&gt;</span> <span class="n">x</span><span class="p">.</span><span class="nf">SendMessageAsync</span><span class="p">(</span><span class="n">It</span><span class="p">.</span><span class="n">IsAny</span><span class="p">&lt;</span><span class="n">ServiceBusMessage</span><span class="p">&gt;(),</span> <span class="n">It</span><span class="p">.</span><span class="n">IsAny</span><span class="p">&lt;</span><span class="n">CancellationToken</span><span class="p">&gt;()),</span> <span class="n">Times</span><span class="p">.</span><span class="nf">Exactly</span><span class="p">(</span><span class="n">times</span><span class="p">));</span>
        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>

    <span class="k">public</span> <span class="n">Then</span> <span class="nf">TheRetriedMessagesHadIncreasingDelays</span><span class="p">()</span>
    <span class="p">{</span>
        <span class="kt">var</span> <span class="n">delays</span> <span class="p">=</span> <span class="k">new</span> <span class="n">List</span><span class="p">&lt;</span><span class="n">TimeSpan</span><span class="p">&gt;();</span>
        <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">.</span><span class="n">Count</span> <span class="p">-</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
        <span class="p">{</span>
            <span class="n">delays</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="m">1</span><span class="p">].</span><span class="n">Created</span> <span class="p">-</span>
                        <span class="n">_host</span><span class="p">.</span><span class="n">TestableQueue1MessageProcessor</span><span class="p">.</span><span class="n">MessageDeliveryAttempts</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">Created</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">for</span> <span class="p">(</span><span class="kt">var</span> <span class="n">i</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="n">i</span> <span class="p">&lt;</span> <span class="n">delays</span><span class="p">.</span><span class="n">Count</span> <span class="p">-</span> <span class="m">1</span><span class="p">;</span> <span class="n">i</span><span class="p">++)</span>
        <span class="p">{</span>
            <span class="n">Assert</span><span class="p">.</span><span class="nf">True</span><span class="p">(</span><span class="n">delays</span><span class="p">[</span><span class="n">i</span> <span class="p">+</span> <span class="m">1</span><span class="p">]</span> <span class="p">&gt;</span> <span class="n">delays</span><span class="p">[</span><span class="n">i</span><span class="p">],</span> <span class="s">$"the interval of retry</span><span class="p">{</span><span class="n">i</span><span class="p">+</span><span class="m">1</span><span class="p">}</span><span class="s">(</span><span class="p">{</span><span class="n">delays</span><span class="p">[</span><span class="n">i</span><span class="p">+</span><span class="m">1</span><span class="p">].</span><span class="n">TotalMilliseconds</span><span class="p">}</span><span class="s">ms) was not larger than the previous retry(</span><span class="p">{</span><span class="n">delays</span><span class="p">[</span><span class="n">i</span><span class="p">].</span><span class="n">TotalMilliseconds</span><span class="p">}</span><span class="s">ms)"</span><span class="p">);</span>
        <span class="p">}</span>

        <span class="k">return</span> <span class="k">this</span><span class="p">;</span>
    <span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>

<p>And that is how we are testing message handling code which uses the <code class="language-plaintext highlighter-rouge">Azure.Messaging.Servicebus</code> client library. Thankyou for reading and hope you find it useful.</p>

<p>All of the code from this post can be found <a href="https://github.com/andrewjpoole/azure-messaging-servicebus-handler-tests">here</a></p>

<p>The title image is from <a href="https://rarehistoricalphotos.com/double-decker-buses-tilt-testing-1933/">here</a></p>

<p>This blog was first published on the <a href="https://www.clear.bank/newsroom/testing-azure-service-bus-handlers">ClearBank tech blog</a></p>]]></content><author><name>Andrew Poole</name></author><category term="testing" /><category term="service bus" /><category term="azure" /><category term="component tests" /><summary type="html"><![CDATA[TL/DR - At ClearBank we love testing and the new Azure.Messaging.ServiceBus package makes testing Service Bus handlers easy at last! Check out how we did it.]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/bust_tilt_testing.jpg" /><media:content medium="image" url="https://www.forkinthecode.net/images/bust_tilt_testing.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Could private network Blockchain enable leaderless consensus in a distributed system? part 1</title><link href="https://www.forkinthecode.net/2019/07/28/could-private-network-blockchain-enable-leaderless-consensus-in-a-distributed-system-part-1.html" rel="alternate" type="text/html" title="Could private network Blockchain enable leaderless consensus in a distributed system? part 1" /><published>2019-07-28T00:00:00+00:00</published><updated>2019-07-28T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2019/07/28/could-private-network-blockchain-enable-leaderless-consensus-in-a-distributed-system-part-1</id><content type="html" xml:base="https://www.forkinthecode.net/2019/07/28/could-private-network-blockchain-enable-leaderless-consensus-in-a-distributed-system-part-1.html"><![CDATA[<p>Ever since I first heard a presentation about Blockchain in a DLL (developer learning lunch) at work a while ago,
I have been convinced that it has a huge number of potential uses.
A list which can be recreated identically in a number of places,
with an easy method of verification which can prove it has not been changed, is surely a very useful thing in software systems.
I am interested in whether a private network Blockchain could be used as the source of truth for shared state
in a distributed system, allowing consensus <em>without</em> needing a leader…</p>

<h2 id="background">Background</h2>

<p>Over the last two or three years, my team has been building a distributed system, a set of dotNetCore microservices using EventStore, Consul and ElasticSearch. There have been times where a certain task needed to completed exactly once even though we had 5 nodes in the cluster, so which node should perform the task? We used advice from a paper in the documentation of Consul, which is a fantastic tool made by Hashicorp. Consul has a concept of sessions and locks, where the nodes in a system can all attempt to place their own session token into the lock, one will succeed and perform the task and the others will wait for their turn.</p>

<h2 id="whats-wrong-with-having-a-leader">Whats wrong with having a leader?</h2>

<p>Even with the help of Consul, which is designed to help with the problems involved with building distributed systems, leader election code is necessarily complex. Only one node should be leader at any one time. All of the other nodes should know who the leader is and that they themselves are not the leader. If the current leader dies, another node should take over without losing any tasks that should have been performed. We found that, for a time sensitive task, even leaders in waiting needed to listen for and attempt to perform all of the leader’s tasks, just in case they became the leader.</p>

<h2 id="super-basic-explanation-of-blockchain">Super basic explanation of Blockchain</h2>

<p>Anyway, back to Blockchain! Blockchain is a brilliant concept of a chain of blocks, where each block contains some data, the previous block’s hash and the block’s own hash. There is a brilliant graphical explanation <a href="http://graphics.reuters.com/TECHNOLOGY-BLOCKCHAIN/010070P11GN/index.html">here</a>, but I will attempt my own explanation anyway…</p>

<p>First we have to explain hashes.
A hash is a unique value that can be mathematically calculated from a given piece of data using an algorithm. The hash of a given piece of data will always be the same, meaning if you send the data to another place along with the original hash, the arrived data can be hashed again and if the two hashes match, you can be sure that arrived data is identical to the original data that was sent. It is not possible to derive the data from the hash, the hash is like a digital fingerprint of the data.</p>

<p>The first block in the chain is special in that its previous hash is null, its called the genesis block.</p>

<p>Each block’s hash contains the previous block’s hash, or in other words the fingerprint of a block is made up of the data in that block AND the previous block’s fingerprint. Its possible to loop through all of the blocks in the chain checking the hashes and proving that the chain is valid. If the chain is instantiated in two locations and both have the same blocks added, the chains (including all of the hashes) will be identical. If one chain has any differences, however small, the hashes will be different from the altered block onwards, the difference between the two chains will be obvious.</p>

<p>So, as long as there are a number of chains (and preferably an odd number) <em>and</em> less than 50% of them have been tampered with, the system can detect the tampering and reject the altered blocks.</p>

<h2 id="whats-the-difference-between-public-and-private-network-blockchain">Whats the difference between public and private network Blockchain?</h2>

<p>In a crypto currency, there is a large public network of nodes, in fact anyone can run a node and have a copy of the chain. The source of truth is therefore completely decentralised and as long as no one party owns more than 50% of the nodes, the system can be trusted.</p>

<p><img src="/images/miningrig.jpg" alt="Blockchain Mining rig" title="Picture of a Blockchain Mining rig" />
Public network Blockchain also has a concept called ‘proof of work’ which makes it non trivial to be able to create the next block, one example is that the hash must start with a certain number of leading zeros, this is where the concept of mining comes from. A number called a nonce is added to the block and if the hash doesn’t meet the constraint (e.g. starting with 11 zeros) the nonce would be incremented and the hash recalculated, this happens repeatedly until the hash meets the constraint. This would probably mean that a special piece of code running on a high-end graphics card on a ‘mining rig’ would have been churning out millions of hashes for about 10 minutes before the next block was found. This is a very simplified explanation, in BitCoin for instance there is also a confirmation process explained <a href="https://coincenter.org/entry/how-long-does-it-take-for-a-bitcoin-transaction-to-be-confirmed">here</a></p>

<p>Its this trust that makes public network blockchain potentially useful for things like currency, banking/financial stuff, supply chain provenance, asset tracking, contracts, medical records etc and loads more.</p>

<p>In a private network, all of the nodes are trusted so there is no need for proof-of-work and the next plain old hash is perfectly fine, which is very fast compared to finding the next hash which starts with 11 zeros.</p>

<h2 id="i-feel-a-side-project-coming-on">I feel a side project coming on…</h2>

<p>So my idea (and I know I’m probably not the first to have had it) is that a private network Blockchain should be able to enable a distributed system to agree on the state of the truth without needing to elect a leader.</p>

<p>Each node in the distributed system would have its own copy of the Blockchain. Any new data added should be broadcasted to the other nodes, who will attempt to verify their Blockchain with the new block on the end. If they cant verify the chain, they will reject the new block, sending a negative response and the original node will have to try again.</p>

<p>So in a cluster with nodeA, nodeB and nodeC, if new data is added to nodeA and nodeB at the same time, one of them (lets say nodeB) will succeed in sending the new block to nodeC first, the other (nodeA) will (having received the new data from nodeB itself) recreate the new block and try again.</p>

<p>This gets more interesting as the number of nodes increases and my guess is that as long as I know the total number of nodes and therefore the size of a quorum (i.e. the number of nodes that represents more than half of the total) a given node should continue pushing a new block as long as it doesn’t receive more than the quorum amount of negative responses and it should definitely continue pushing a block if it receives more than the quorum amount of positive responses! The larger the cluster the more chance of competition, this is the bit that I am most looking forward to experimenting with.</p>

<p>I needed a concrete use case to test my theory and happened to have 50 odd Gb of family photos which need sorting so my plan was to build a WebApi which will allow me to store and retrieve files (mostly photos) and to define and search on metadata associated with the files I have stored. The files will be stored in an Azure blob store and the metadata will be stored in a Blockchain. The WebApi should run on multiple nodes as a distributed system, where all nodes are capable of reading and writing data. Whenever data is written to a node it should broadcast the new data to the other nodes and therefore all nodes should have an identical Blockchain.</p>

<h2 id="how-will-i-know-when-the-question-has-been-answered">How will I know when the question has been answered?</h2>

<p>I guess I will have my system up and running, receiving uploaded photos as fast as possible for a sustained period of time, while being able to simultaneously make read successful requests and metadata searches. At any point in time, I should be able to check the latest block’s hash matches across the cluster.</p>

<h2 id="progress-so-far">Progress so far</h2>

<p>So far, I have:</p>

<ul>
  <li>developed the basic dotNetCore WebApi service with Swagger, starting using LiteDb behind an abstraction</li>
  <li>developed my Blockchain implementation with unit tests</li>
  <li>developed a P2P module using the excellent GRPC</li>
  <li>developed a Blockchain database and switched it in place of LiteDB.</li>
  <li>written some NUnit integration tests that add 3000 random strings of data to a random node in a cluster of three, as fast as possible and check that the Blockchains are identical at the end</li>
  <li>persisted the chain to an Azure blob after each write</li>
  <li>added some ridiculously fast indexing using the humble Dictionary class.</li>
  <li>added logging to Elasticsearch</li>
  <li>have centralised configuration in Hashicorp Consul</li>
</ul>

<h2 id="next-steps">Next steps</h2>

<p>Next, I plan to:</p>

<ul>
  <li>put the source onto GitHub</li>
  <li>write tests which prove that the cluster does not get into a split brain scenario after two coincident writes</li>
  <li>improve the Blockchain persistence</li>
  <li>have new nodes initialise their Blockchains from the blob store</li>
  <li>periodically check for and prune dead nodes from the list.</li>
  <li>develop an Angular frontend</li>
  <li>add some kind of decent load testing</li>
</ul>

<h2 id="future-ambitions">Future ambitions</h2>

<ul>
  <li>I need an uploader application.</li>
  <li>I want to add indexing, including geospatial metadata, in ElasticSearch</li>
  <li>I want to deploy the thing to Azure Kubernetes Service.</li>
  <li>Long term I’m thinking of using Cognitive services Face Api and maybe some machine learning to fill in missing Tags etc.</li>
</ul>

<p>Thanks for reading!</p>]]></content><author><name>Andrew Poole</name></author><category term="blockchain" /><category term="distributed systems" /><category term="leaderless consensus" /><summary type="html"><![CDATA[Ever since I first heard a presentation about Blockchain in a DLL (developer learning lunch) at work a while ago, I have been convinced that it has a huge number of potential uses. A list which can be recreated identically in a number of places, with an easy method of verification which can prove it has not been changed, is surely a very useful thing in software systems. I am interested in whether a private network Blockchain could be used as the source of truth for shared state in a distributed system, allowing consensus without needing a leader…]]></summary><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://www.forkinthecode.net/images/chain.jpg" /><media:content medium="image" url="https://www.forkinthecode.net/images/chain.jpg" xmlns:media="http://search.yahoo.com/mrss/" /></entry><entry><title type="html">Parallels between software and music</title><link href="https://www.forkinthecode.net/2019/07/17/parallels-between-software-and-music.html" rel="alternate" type="text/html" title="Parallels between software and music" /><published>2019-07-17T00:00:00+00:00</published><updated>2019-07-17T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2019/07/17/parallels-between-software-and-music</id><content type="html" xml:base="https://www.forkinthecode.net/2019/07/17/parallels-between-software-and-music.html"><![CDATA[<p>I was recently challenged during a one-to-one with my mentor at work to write a blog about the links/parallels between software development and music. My mentor has an interest in the promotion of STEM (science, technology, engineering, arts and maths) and STEAM (which adds arts in too). I thought this was an interesting idea so I’m having a go!
The first thing that pops into my head when I think about software engineering OR when I think about music is creativity…</p>

<h3 id="creativity">Creativity</h3>

<p>I think the main reason I love software engineering is the sheer creativity, we start with a defined a bunch of building blocks (a language and base class library etc) then we go about the process of solving problems or realising ideas using a limitless amount of these blocks, sometimes creating higher level reusable blocks, sometimes pulling in someone elses. With cloud scale, the only limits really are your imagination!</p>

<p>From my personal experience, I see a strong link between my <del>obsession with</del> career in software with a love of Lego as a child. I asked for Lego at every opportunity and enjoyed building the official model, but only ever once, after that I would add the pieces to my very large box and build whatever I wanted. (At college, I built a prototype of a racing car in Lego that had working accelerator, brakes, a clutch and a 3 speed gearbox and I had so much Lego that it was all colour coordinated and everything!)</p>

<p>What I’m not sure about is whether the Lego gave me that creativity or just gave expression to it. My son likes Lego but not in the same way I loved it. I see a similar thing with children who love Minecraft.</p>

<p>Anyway, back to music. Music is obviously a hugely creative thing, although slavishly learning piano pieces for an exam is certainly not fun. I learnt trumpet classically to the point where I could read music by sight fairly well, even transposing into different keys, but I was so frustrated that I couldn’t improvise to save my life! I always longed to be able to improvise! I certainly enjoyed playing music in a group where the sheet music was the key to transforming a set of individual solo efforts into something that was more than the sum of the parts. That was definitely still a creative thing, but different to creating something from scratch. Similar to building the official Lego models.</p>

<h3 id="personal-software-development-practice-and-personally-playing-an-instrument">Personal software development practice and personally playing an instrument</h3>

<p>At first, when thinking about what to write, I was looking for parallels between personal software engineering practice and personally playing a musical instrument, there are definitely some: practice, research and learning by reading etc, even going to a conference to hear a particular speaker is similar to going to your favourite band’s gig or a clinic with your favourite bass player etc. Also the concept of a music teacher is quite like that of a mentor or senior in a team who has an interest in inspiring the team members to reach their potential by passing on what they have learnt. But I was sure there must be something more compelling that those!</p>

<h3 id="comparison-of-a-software-development-team-and-a-band">Comparison of a software development team and a band</h3>

<p>I switched to considering the similarities of a software engineering team and a band and I think there is much more to learn.</p>

<p>Playing in a band can be one of the greatest things in life. I am going to focus on what it is that makes a great experience of playing a song in a band, when everything works and a lovely piece of music is the result. I’m thinking about a band with guitars and drums rather than say a brass band or orchestra, although I guess the same applies.</p>

<p><img src="/images/DMB2013.jpg" alt="Dave Matthews Band, May 2013" title="Dave Matthews Band, May 2013" /></p>

<h4 id="the-groove">The Groove</h4>

<p>A song will have a ‘groove’ which is a kind of rhythmic repeating pattern which is established by the drummer and bass player. The pattern will usually feature accents using the Kick and Snare which the bass player also picks up in the notes they play. The groove sets the ‘feel’ of the song and will be influenced by the style of the music and/or other songs or favourite artists. For instance, in Reggae music the groove is usually swung and places a heavy emphasis on the off beat, whereas in a rock groove it is normally played straight and there is a kick on beats 1 and 3 and a snare on 2 and 4. In western music, which is normally structured in 8 bar sections, there would probably be different grooves for different sections of a given song, one for the verses, one for choruses and another for the bridge etc. At the end of a section there would normally be some kind of fill which is where the drummer and/or bass player would play a something slightly different usually ending in a hit on a cymbal. The groove also has a tempo, which is the speed at which the song is played.</p>

<p>In software…</p>

<p>I’m not sure what the groove equates to in software? It could the technology stack chosen for the job or the agile methodology which shapes the process. There should definitely be a rhythm in a software engineering team and it should feel like everyone in the team is pulling together in one direction and with one shared aim. In the same way that groove has influences from styles or other songs or artists, the members of the team will have had past experiences of technologies or design patterns and will hopefully bring in those experiences where appropriate.</p>

<h4 id="listen-to-each-other-and-work-together">Listen to each other and work together</h4>

<p>Probably the most important thing when playing music in a group is to listen to each other. Each person should hold the aim of creating some lovely music more highly important than say personal recognition or being so loud that they drown out everyone else. When each player listens to the others they can stay in time, stay grounded on the groove, they can leave space for each other and play things that compliment the other parts. This is what turns of bunch of separate noises into some music. Band members get to know each other well and begin to ‘play off’ each other where the idea of one person can inspire another idea in someone else. Suggesting an idea can be quite a daunting thing to do because it makes you a bit vulnerable, you need to know that the other band members will not reject ideas harshly.</p>

<p>In software…</p>

<p>I think there are striking similarities here, in a software engineering team, members should be working together and aware of what the other members are doing. They should help each other when needed and ensure that when separate streams of work are going on in parallel, the work can be integrated easily when it comes back together.</p>

<p>In terms of suggesting and trying out ideas, this is crucial:</p>
<blockquote>
  <p><strong>suggestions, questions and contributions to discussion are not only wanted, they are absolutely needed from every member of the team! There are no stupid questions!</strong></p>
</blockquote>

<p>I suggest you drill this into each and every member of your team!</p>

<p>The key to working together well is communication. Team members should be able to inspire each other, to respectfully challenge each other, to show flexibility and to negotiate and compromise. You need the culture to be friendly, open and honest for this to happen. I’ve found that admitting your own mistakes, failures and weaknesses really helps with this. You want your team members to be comfortable showing vulnerability, to admit when they don’t know or understand something or to be able to say when they are just having a terrible day.
Once this does start to happen, you will have a team who feels ‘safe to fail’ having the emotional security they need to have ideas, make suggestions, try things out, learn from failures knowing no-one is going to punish them etc. Most importantly they will realise that they have a voice and an important contribution to add, which will make them enjoy their job and feel fulfilled.</p>

<h4 id="dynamics">Dynamics</h4>

<p>A good song feels like its going somewhere, it starts in one place and builds to another, there can be quiet sections, sections which build and louder sections.</p>

<p>In software…</p>

<p>In software engineering teams, we tend to focus on a consistently high velocity, I wonder if teams should plan quieter times or sprints with a different focus? I have heard of the concept of ‘firebreak’ sprints where the team is allowed a whole sprint where they can decide what to work on. This might be a piece of tech debt or a new concept idea or some kind of test or deployment tool etc. Even the concept of a ‘sprint’ has always seemed a bit wrong to me - as no-one can keep sprinting forever (however much business like the idea!) its a short exhausting burst. I prefer a decent paced long distance event, which might be more like Kanban, but thats probably a different post.</p>

<h4 id="practices-and-performances">Practices and performances</h4>

<p>If a band has a performance or tour coming up, they will practice and practice and practice some more. They will know their parts so well they could play them in their sleep and then when the time comes they can deliver a perfect performance to their fans.</p>

<p>In software…</p>

<p>I think this could have some relevance in the area of deployments or migrations. I’ve worked in places where deployments were practiced, but rarely in a sufficiently live-like environment to promote serious confidence. Maybe if we thought that people would be watching we would do things differently?</p>

<h2 id="to-sum-up">To sum up</h2>

<p>I think there are a lot of interesting similarities between bands playing music and software engineering teams, some more obvious and some more subtle. There may be aspects of both which would benefit the other in some way. The analogy of course breaks after a while, take pair programming for instance, that would be very interesting in a band! Thanks for reading.</p>]]></content><author><name>Andrew Poole</name></author><category term="music" /><category term="HealthyTeams" /><summary type="html"><![CDATA[I was recently challenged during a one-to-one with my mentor at work to write a blog about the links/parallels between software development and music. My mentor has an interest in the promotion of STEM (science, technology, engineering, arts and maths) and STEAM (which adds arts in too). I thought this was an interesting idea so I’m having a go! The first thing that pops into my head when I think about software engineering OR when I think about music is creativity…]]></summary></entry><entry><title type="html">Make your CV work for you!</title><link href="https://www.forkinthecode.net/2019/07/14/make-your-cv-work-for-you.html" rel="alternate" type="text/html" title="Make your CV work for you!" /><published>2019-07-14T00:00:00+00:00</published><updated>2019-07-14T00:00:00+00:00</updated><id>https://www.forkinthecode.net/2019/07/14/make-your-cv-work-for-you</id><content type="html" xml:base="https://www.forkinthecode.net/2019/07/14/make-your-cv-work-for-you.html"><![CDATA[<p>Some things happened at work recently which made me wonder whether it was time to think about moving on.
I always intended to go to the odd practice interview, but never managed it. So I thought I’d update my CV, change my LinkedIn status and see what happens. I tried out some new ideas with my CV and ended up accepting the offer of a near perfect job (for me) after about 25 working days…</p>

<p>I never intended to stay at one company for 5 1/2 years, but I did get a promotion from senior to lead 3 1/2 years ago and was committed to staying for the duration of a large project which was likely to last another 2 years.
The annoying things at work were winding me up quite a lot, to the point of losing sleep.
One particular sleepless night, with everything swirling around in my mind, I was wondering how I would try to find my next company.</p>

<p>I had learned through the course of several past jobs and projects quite a few things that I did and did not like, but the tricky bit seemed to be how would I measure a prospective company against those opinions in the time it takes to have an interview?
Then I had the idea of creating my ideal ‘Company Spec’, I sat up in bed, fired up my laptop and started typing, exactly one hour later having dumped all my thoughts, I finally dropped off to sleep, feeling much better.</p>

<h3 id="company-spec">Company spec</h3>

<p>What I meant was a set of points describing what I wanted from my next employer in the same way that an employer would describe what they wanted in their next employee in a job spec.
I’ll include my actual company spec below.</p>

<p>Firstly, I got positive comments from recruiters, but also positive feedback from the first interesting looking company that I decided to pursue, in fact I discussed several points from the Company Spec with the CTO of that company in the telephone interview that followed and then the face-to-face interview that followed that! I ended up seriously considering and eventually accepting a job with that same company!</p>

<p>I found that my company spec did several things:</p>

<ul>
  <li>it let the company know that I have opinions and think things though</li>
  <li>it is source of stories to tell - the reasons I have each opinion.</li>
  <li>its a source of questions for me, as you can always take a copy of your CV into an interview and you can refer to it when your mind inevitably goes blank when they ask if you have any questions.</li>
  <li>it let the company weigh themselves up against the points in my list</li>
  <li>it potentially could have helped a thorough recruiter in not wasting my time and theirs on a job which clearly did not compare favourably with my list.</li>
</ul>

<p>By the end of the interview and certainly by the time I received an offer, we had discussed all of the points in my company spec in detail and to the point that I was pretty sure it was a company I could work for and I think they were fairly sure I was someone they could employ.</p>

<h3 id="include-an-interesting-side-project">Include an interesting side project</h3>

<p>The other thing I did was to place a short section about an interesting side project and what progress I’d made with it. In my case I am convinced that private network blockchain can solve the problem of consensus in a distributed system without needing a leader, so I have a project in which I am trying to prove it. I am also using my project to learn about containers and Azure, both of which I haven’t used much in a commercial context.
I supposed a decent open source project would be even better, but any interesting project or problem to solve would work. As long as you can talk about it confidently when the questions come, I talked about my intentions for future architecture and some stretch goals. I think this would be especially useful if the projects you have been working on are not utilising modern architectures or design patterns, as it shows awareness of modern thinking and a bit of initiative on your part to go above and beyond to learn them.</p>

<h2 id="both-of-these-are-really-just-a-way-of-steering-the-conversation-to-something-you-can-talk-about-enthusiastically">Both of these are really just a way of steering the conversation to something you can talk about enthusiastically</h2>

<p>My final CV layout was:</p>

<ul>
  <li>Name, address, basic info etc</li>
  <li>Summary list of languages/technologies with rough estimate of years/months of experience</li>
  <li>Short section on my side project (don’t hide this bit!)</li>
  <li>My Company Spec</li>
  <li>Work experience</li>
  <li>Education</li>
  <li>Short personal statement</li>
</ul>

<h2 id="the-actual-company-spec-section-i-included">The actual company spec section I included</h2>

<p>Probably not best to copy mine as you’ll need to talk about them and the experiences good and bad which lead you to the opinion, but this is what worked for me:</p>

<p><img src="/images/CompanySpec.jpg" alt="Screenshot of my Company Spec, from my CV" title="Screenshot of my Company Spec, from my CV" /></p>

<h2 id="in-conclusion">In Conclusion</h2>

<p>I’m not saying that my company spec and side project sections in my CV got me my new job, but they certainly helped with the content of the conversations in the two interviews I had and certainly left me feeling confident about the ‘fit’ of the company for me. This was definitely the smoothest recruiter-&gt;telephone-&gt;face-to-face-&gt;offer-&gt;negotiation-&gt;acceptance process I’ve ever had. I have notice to work before I can start my new job and we will have to wait and see how things go but I’m feeling very excited about it!</p>]]></content><author><name>Andrew Poole</name></author><category term="CompanySpec" /><category term="CV tricks" /><category term="HealthyTeams" /><summary type="html"><![CDATA[Some things happened at work recently which made me wonder whether it was time to think about moving on. I always intended to go to the odd practice interview, but never managed it. So I thought I’d update my CV, change my LinkedIn status and see what happens. I tried out some new ideas with my CV and ended up accepting the offer of a near perfect job (for me) after about 25 working days…]]></summary></entry></feed>