<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Grant Hair</title>
    <description>The latest articles on Forem by Grant Hair (@granthair5).</description>
    <link>https://forem.com/granthair5</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F158744%2Fc74bc5d5-2ae3-4f01-8898-5084215d465c.png</url>
      <title>Forem: Grant Hair</title>
      <link>https://forem.com/granthair5</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/granthair5"/>
    <language>en</language>
    <item>
      <title>How delegating handlers bit me in the ass and how I tested them</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Mon, 03 Jul 2023 08:39:05 +0000</pubDate>
      <link>https://forem.com/granthair5/how-delegating-handlers-bit-me-in-the-ass-and-how-i-tested-them-1n67</link>
      <guid>https://forem.com/granthair5/how-delegating-handlers-bit-me-in-the-ass-and-how-i-tested-them-1n67</guid>
      <description>&lt;p&gt;My use case was the following: &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Add a delegating handler to add a bearer token to an api call that will either pull a JWT from a 3rd party api endpoint or pull it from memory cache. If we get an unauthorized response we want to bust the cache and repopulate the value with a call to an api&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My main issue with testing this logic was in the following code &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;


&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;MakeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;MakeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isRetry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SetAuthHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;isRetry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiException&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Unauthorized&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!&lt;/span&gt;&lt;span class="n"&gt;isRetry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// if due to 401 and it wasn't a new token then retry with a new token&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;MakeRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;

                &lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"ApiException making request to {url}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RequestUri&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;When &lt;code&gt;return await base.SendAsync(request, cancellationToken);&lt;/code&gt; was called the base class would then try and send the actual api request which would result in a 404 because my test was setup to send requests to "blah.blah" or something. In my use case it was a 3rd party api to send SMS messages to users not something I wanted to be doing for real life. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FU8UDIeRLG6kAAAAC%2Ffor-real-life-bluey.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.tenor.com%2FU8UDIeRLG6kAAAAC%2Ffor-real-life-bluey.gif" alt="For real life?"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My test code looked something kinda like this (Moq-ed Spaghetti) after a couple days and a lot of head banging trying to get stuff mocked out and trying to use Moq &lt;code&gt;Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected().Protected()&lt;/code&gt; or something I can't remember it was a bit of a blur haha&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpthkxd685vy3asqash3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftpthkxd685vy3asqash3.png" alt="Moq-ed Spaghetti"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I came across this stack overflow answer and stuff started to make sense. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/a/37219176/9057687" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/37219176/9057687&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By setting the &lt;code&gt;InnerHandler&lt;/code&gt; of my custom delegating handler to just a stubbed out response like this I was able to avoid the actual sending of the request and just return an Accepted response.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestHandler&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;DelegatingHandler&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;SendMessageResponse&lt;/span&gt; &lt;span class="n"&gt;_sendMessageResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;MessageId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AF97201F-F324-4CD1-A513-42811FA962B4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpRequestMessage&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpResponseMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accepted&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Content&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonContent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_sendMessageResponse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;

            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromResult&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then my test code could be simplified massively to something like this &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyTestHandlerThatIWantToTestShould&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;JwtValue&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
            &lt;span class="s"&gt;"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0ZXN0IjoidGVzdCJ9.elSSvs4awH3XEo1yZGTfZWjgCXcfyy_TBRyCSCT3WbM"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ILogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;MyTestHandlerThatIWantToTest&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IMemoryCache&lt;/span&gt; &lt;span class="n"&gt;_memoryCache&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryCache&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryCacheOptions&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;MyTestHandlerThatIWantToTest&lt;/span&gt; &lt;span class="n"&gt;_handlerThatIWantToTest&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;IOptions&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SmsApiConfiguration&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;SendMessageResponse&lt;/span&gt; &lt;span class="n"&gt;_sendMessageResponse&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;MessageId&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"AF97201F-F324-4CD1-A513-42811FA962B4"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;MyTestHandlerThatIWantToTestShould&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_config&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Extensions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SmsApiConfiguration&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;ApiBaseAddress&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://any-old-value.website.com/api-test-mocked"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;ApiToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Guid&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;NewGuid&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;JwtTokenCacheKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"CacheKey"&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;mockHttp&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MockHttpMessageHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="n"&gt;mockHttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;When&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"{'jwt' : '"&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;JwtValue&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"'}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockHttp&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_handlerThatIWantToTest&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MyTestHandlerThatIWantToTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;PopulateBearerTokenValue_When_ARequestToSendSmsIsSend&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpRequestMessage&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// This is the magic line I'd say&lt;/span&gt;
            &lt;span class="n"&gt;_handlerThatIWantToTest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InnerHandler&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TestHandler&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;invoker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HttpMessageInvoker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_handlerThatIWantToTest&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// act&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;invoker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Accepted&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;responseObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SendMessageResponse&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;responseObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_sendMessageResponse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MessageId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Headers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Authorization&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Parameter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;_memoryCache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JwtTokenCacheKey&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;JwtValue&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In my test I can assert that an auth header was added, the value was added to the memory cache and that an accepted response was returned. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8hy87m8yd4stt4rth9g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft8hy87m8yd4stt4rth9g.png" alt="My test passed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everyone probably already knows this stuff but it kinda stumped me for a bit I think mainly because we are using Refit for our API calls instead of using HttpClient everywhere so stuff was a wee bit different for me and took a bit to get my head around. We had a bit of chicken and egg situation for a while with the api that both sent the request and obtained the JWT as it was technically part of the same Refit interface but we needed to pass the interface to get the jwt before we could make the request so DI became a bit tricky hence the usage of HttpClient for getting the JWT and refit for sending the actual request. &lt;/p&gt;

&lt;p&gt;I'm pretty sure there are a few ways to refactor this code or improve it but the tickets in ready to deploy now so that is a tale for another sprint haha. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Shout out to:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/richardszalay/mockhttp" rel="noopener noreferrer"&gt;https://github.com/richardszalay/mockhttp&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/moq/moq" rel="noopener noreferrer"&gt;https://github.com/moq/moq&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://fluentassertions.com" rel="noopener noreferrer"&gt;https://fluentassertions.com&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;👋&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>testing</category>
    </item>
    <item>
      <title>I used my first ever Expression&lt;Func&lt;TInput, TOutput&gt;&gt; today to create reusable LINQ Queries</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Fri, 19 Nov 2021 11:49:22 +0000</pubDate>
      <link>https://forem.com/granthair5/i-used-my-first-ever-expressionfunctinput-toutput-today-to-create-reusable-linq-queries-48p1</link>
      <guid>https://forem.com/granthair5/i-used-my-first-ever-expressionfunctinput-toutput-today-to-create-reusable-linq-queries-48p1</guid>
      <description>&lt;p&gt;Up to this point in my career I have yet to reuse a Select lambda in my LINQ queries, today that changed. &lt;/p&gt;

&lt;p&gt;I was messing around with something for a technical session within my team when I noticed I had the exact same code for 2 Select functions. &lt;/p&gt;

&lt;p&gt;Basically I wanted to Select my DB entity type to a Domain Transfer Object type. I could've done this through some mapping or whatever but I chose this way to show off the barebones of what I was trying to show and tell at our tech session. &lt;/p&gt;

&lt;p&gt;My code looks like this, I have a VERY basic API (that uses probably 0 best practices) that returns various information about Golf courses, scores, handicaps etc etc. &lt;/p&gt;

&lt;p&gt;Side note, I love golf, its a great excuse to get outdoors which is probably going against the grain in a Covid fuelled world but anyways I'll keep going. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-48B1JW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cm4ofy9sd88mu62fsxx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-48B1JW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8cm4ofy9sd88mu62fsxx.png" alt="Golf Stuff" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I managed to take a pretty sick photo of a tree whilst golfing at the weekend. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x4oBhmGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iru43yylgbg8i110hwd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x4oBhmGy--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iru43yylgbg8i110hwd1.png" alt="Tree" width="880" height="1173"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Where was I... ah yes the codes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CourseDataIntegrationServices&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ICourseDataIntegrationServices&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;GolfScoresDbContext&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;CourseDataIntegrationServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GolfScoresDbContext&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;_context&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CourseDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GetAllCourses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Courses&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Holes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_selectCourseToCourseDto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;CourseDto&lt;/span&gt; &lt;span class="nf"&gt;GetCourseById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Guid&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;_context&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Courses&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Include&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Holes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_selectCourseToCourseDto&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;Expression&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Func&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Course&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CourseDto&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;_selectCourseToCourseDto&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;CourseDto&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Holes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Holes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;HolesDto&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;HandicapIndex&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HandicapIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Par&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Par&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Number&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Yardage&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Yardage&lt;/span&gt;
                &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;OrderBy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;Par&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Par&lt;/span&gt;
            &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nice thing about this is that I know have a reusable way of mapping my DB entity to my DTO without the need of a 3rd part NuGet package and tbh the code is pretty plain vanilla in terms of added sprinkles. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;Expression&amp;lt;Func&amp;lt;Course, CourseDto&amp;gt;&amp;gt;&lt;/code&gt; in your head can become &lt;br&gt;
&lt;code&gt;Expression&amp;lt;Func&amp;lt;MyInputType, MyOutputType&amp;gt;&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;I can take the above one step further by writing a second Expression&amp;gt; for my Hole selection...don't be nasty. &lt;/p&gt;

&lt;p&gt;I think I will leave that for another day. &lt;/p&gt;

&lt;p&gt;Anyways I hope this has been of some help to those looking to create reusable select criteria for LINQ queries. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GI4eVlCq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8t6vqoqtxvaejk2y2cv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GI4eVlCq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n8t6vqoqtxvaejk2y2cv.png" alt="Ciao for now" width="670" height="650"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
    </item>
    <item>
      <title>Cypress e2e testing with Google Maps Autocomplete</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Tue, 04 May 2021 08:48:04 +0000</pubDate>
      <link>https://forem.com/granthair5/cypress-e2e-testing-with-google-maps-autocomplete-42hp</link>
      <guid>https://forem.com/granthair5/cypress-e2e-testing-with-google-maps-autocomplete-42hp</guid>
      <description>&lt;p&gt;During my working day I encountered a problem. &lt;/p&gt;

&lt;p&gt;I needed to be able to drive a Google Maps Autocomplete text input through Cypress Tests. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.cypress.io" rel="noopener noreferrer"&gt;https://docs.cypress.io&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete" rel="noopener noreferrer"&gt;https://developers.google.com/maps/documentation/javascript/examples/places-autocomplete&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1hosm25begnyz1qkbcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn1hosm25begnyz1qkbcg.png" alt="Gmaps Autocomplete"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see above we get some suggestions as you type in the search box. &lt;/p&gt;

&lt;p&gt;Now this is extremely easy to test manually, just jab in a place and click on a suggestion. &lt;/p&gt;

&lt;p&gt;Cypress testing this not so much. &lt;/p&gt;

&lt;p&gt;I scratched my head for hours trying to figure out how I could target that little suggestions list served back from Google Maps. &lt;/p&gt;

&lt;p&gt;I went through the following google search results &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/cypress-io/cypress/issues/14598" rel="noopener noreferrer"&gt;https://github.com/cypress-io/cypress/issues/14598&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/53039165/cypress-test-google-places-autocomplete-not-functioning" rel="noopener noreferrer"&gt;https://stackoverflow.com/questions/53039165/cypress-test-google-places-autocomplete-not-functioning&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/bahmutov/cypress-geolocation-example" rel="noopener noreferrer"&gt;https://github.com/bahmutov/cypress-geolocation-example&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://glebbahmutov.com/blog/cypress-geolocation/" rel="noopener noreferrer"&gt;https://glebbahmutov.com/blog/cypress-geolocation/&lt;/a&gt; &lt;/p&gt;

&lt;h3&gt;
  
  
  The Solution
&lt;/h3&gt;

&lt;p&gt;The Solution for me was something like the following &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;


&lt;span class="nx"&gt;completeBranchPage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enterText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enterLocationInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dumfries&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pac-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enterText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enterLocationInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{downarrow}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;enterText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;enterLocationInput&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{enter}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;latInput&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;have.value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dumfriesLat&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lngInput&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;have.value&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dumfriesLong&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The magic piece of the puzzle for me was making sure that the gmaps  suggestion items were actually there before I tried to choose one of them. &lt;/p&gt;

&lt;p&gt;I did this with the following line of code where &lt;code&gt;.pac-item&lt;/code&gt; is the class of the Gmaps Autocomplete suggestions&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.pac-item&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10000&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;should&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;be.visible&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Huge shoutout to this stack overflow answer, &lt;a href="https://stackoverflow.com/a/60065672/9057687" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/60065672/9057687&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I now have a passing test, WOOHOO!!! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqjhzsxay4b8fk9gxx4x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faqjhzsxay4b8fk9gxx4x.png" alt="Passing cypress test"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Where's the code you jabroni?
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/GrantHair5/cypress-google-maps-autocomplete" rel="noopener noreferrer"&gt;https://github.com/GrantHair5/cypress-google-maps-autocomplete&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have created a small example repo. &lt;/p&gt;

&lt;p&gt;You will need to add your own Google Maps API Key secret in the fashion of an environment variable or a .NET user secret. &lt;/p&gt;

&lt;p&gt;User secret would be like the following &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

{
  "GmapsApiSecrets": {
    "ApiKey": "MY SUPER DOOPER SECRET KEY"
  }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Please feel free to fork or clone down that repo and have a play around with the code. &lt;/p&gt;

&lt;p&gt;For anyone who has not used cypress testing in the past I'd whole heartedly recommend it. Massive shout out to our Automation Tester &lt;a href="https://github.com/karenpetrie" rel="noopener noreferrer"&gt;https://github.com/karenpetrie&lt;/a&gt; for introducing us to the mysterious ways of automated testing. &lt;/p&gt;

&lt;p&gt;It is baller. &lt;/p&gt;

&lt;p&gt;Anyways, I'm out, hope this is of help to someone&lt;/p&gt;

&lt;p&gt;Bye 👋 &lt;/p&gt;

</description>
      <category>javascript</category>
      <category>googlecloud</category>
      <category>programming</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Decremental Improvements aka The Longest Blog Post Ever</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Wed, 28 Apr 2021 08:20:37 +0000</pubDate>
      <link>https://forem.com/granthair5/decremental-improvements-aka-the-longest-blog-post-ever-6eb</link>
      <guid>https://forem.com/granthair5/decremental-improvements-aka-the-longest-blog-post-ever-6eb</guid>
      <description>&lt;p&gt;Photo by &lt;a href="https://unsplash.com/@pawel_czerwinski?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Paweł Czerwiński&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/bin?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  tl;dr;
&lt;/h3&gt;

&lt;p&gt;This conference video from HackConf Bulgaria 2019 (I attended yay) was the catalyst for me. &lt;/p&gt;

&lt;p&gt;Bozhidar Batsov: The Groundhog Development Method &lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/aI0rGBMZkp4"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1&gt;
  
  
  Intro
&lt;/h1&gt;

&lt;p&gt;This post is entirely opinionated and is based on my experiences, please take it with a pinch of salt. &lt;/p&gt;

&lt;p&gt;I apologise it is lengthy.&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;Since the beginning of time (1 January 1970 00:00:00 UT) programmers have been striving to write code. &lt;/p&gt;

&lt;p&gt;For sometime we wrote very little code at all &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vmqtphSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfnbe42x68uuzyke5yv4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vmqtphSX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zfnbe42x68uuzyke5yv4.jpg" alt="Punch Cards"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then we began to write lots of code (obviously not just for Hello World) &lt;br&gt;
&lt;a href="https://en.wikipedia.org/wiki/Plankalk%C3%BCl"&gt;https://en.wikipedia.org/wiki/Plankalkül&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ShE_ZC4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3jgbyzfw95djnyjfwj1a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ShE_ZC4Z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3jgbyzfw95djnyjfwj1a.png" alt="Plankalkül Hello World"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then programming began to get a little easier&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d7lCeQcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4q31bn4pbsp42u603722.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d7lCeQcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4q31bn4pbsp42u603722.jpg" alt="Fortran"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://ourcodingclub.github.io/tutorials/fortran-intro/"&gt;https://ourcodingclub.github.io/tutorials/fortran-intro/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fast forward sometime and you find yourself in the land of "high level languages" you know the simple stuff that even your wee old granny could write from her rocking chair... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--re7kL0GI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qu6ohqi1lozc3vyu39gx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--re7kL0GI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qu6ohqi1lozc3vyu39gx.jpeg" alt="C Hello World"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;That is an implementation of hello world in C btw&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.quora.com/What-is-the-most-complicated-C-code"&gt;https://www.quora.com/What-is-the-most-complicated-C-code&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;I see where you are going with this... &lt;/p&gt;

&lt;p&gt;The issue is the lines of code and the fact that as a native English speaker I can't properly say what I am trying to do with these languages... &lt;/p&gt;

&lt;p&gt;We need more packages, we need more abstraction. &lt;/p&gt;

&lt;p&gt;So we gave the world packages. We gave the world languages that were pretty much plain English. What did they do with it? They threw it right back in our faces. &lt;/p&gt;

&lt;p&gt;"I amn't using a package it could have anything in it." - They say as they proceed to write the exact same code as in the package. &lt;/p&gt;

&lt;p&gt;Dogfooding innit.  &lt;/p&gt;

&lt;p&gt;Then began the process I like to call "meme based programming" &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--W_TzspHV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnbm4cbvkfrtmgwnn2tx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--W_TzspHV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bnbm4cbvkfrtmgwnn2tx.jpg" alt="hadouken code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l8Xz_sMc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkf9p6bxz39fb0rdpb4l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l8Xz_sMc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jkf9p6bxz39fb0rdpb4l.png" alt="c plos plos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Kq03ansn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t50sehniy7hd11rlg837.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Kq03ansn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t50sehniy7hd11rlg837.png" alt="braces"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Off topic, c'mon Grant get back here!
&lt;/h2&gt;

&lt;p&gt;Anyways the point I am making is that as programmers... we suck... we write crap that we aren't proud of on a daily basis. &lt;/p&gt;

&lt;p&gt;It's ok though because we always have a solution... right.  &lt;/p&gt;

&lt;p&gt;If someone was to hire me to write code with the processing power of a calculator, without my safety blanket of C# without ReSharper, without Google, without Stack Overflow to send a rocket to the moon I would end up with at least something on fire.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XzEGj26e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn1w4u1ajdi8oipocp4r.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XzEGj26e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rn1w4u1ajdi8oipocp4r.jpg" alt="This is fine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I still don't get it
&lt;/h2&gt;

&lt;p&gt;Anyways enough memes and stuff... &lt;/p&gt;

&lt;p&gt;The point is we will write some garbage, sometimes we can't control this. Sometimes that hot steamy garbage was the best thing we could come up with at that point. &lt;/p&gt;

&lt;p&gt;But... &lt;/p&gt;

&lt;p&gt;How often do you look at that hot steamy garbage and think "What was I thinking?" &lt;/p&gt;

&lt;p&gt;Probably quite a lot. &lt;/p&gt;

&lt;p&gt;But due to scope and other constraints you never do anything about it because hey "It works" - (TM) every programmer ever at some point.&lt;/p&gt;

&lt;h2&gt;
  
  
  Some solutions I try to use.
&lt;/h2&gt;

&lt;p&gt;Lets say you have a little bit of "slack time" you managed to get that feature done a few days before expected. &lt;/p&gt;

&lt;p&gt;There is a piece of code that you didn't write for this feature but it is in the same class or file that you are working in. It has been there for sometime. It is absolute hot garbage. I am talking this kinda code &lt;/p&gt;

&lt;p&gt;&lt;a href="https://levelup.gitconnected.com/reviewing-the-worst-piece-of-code-ever-db2df8730c76"&gt;https://levelup.gitconnected.com/reviewing-the-worst-piece-of-code-ever-db2df8730c76&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://shitcode.net/worst"&gt;https://shitcode.net/worst&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"Most" of them are "easily" refactored but you can guarantee that I have written some awful code in my time. The kind that you look back at and think "Did I fall and hit my head that day?" &lt;/p&gt;

&lt;p&gt;Take some time, refactor the garbage. &lt;/p&gt;

&lt;p&gt;Before you do that find out something extremely important. &lt;/p&gt;

&lt;p&gt;Does anyone actually use this garbage. &lt;/p&gt;

&lt;p&gt;What I mean by this is... &lt;/p&gt;

&lt;p&gt;Lets say your garbage code is on a page that 0.46% of users (&amp;lt;1%) actually visit. Is there much point keeping that garbage code page around? &lt;/p&gt;

&lt;p&gt;If that 0.46% of users is the directors of the company then probably. Discover who uses what and why they need it. &lt;/p&gt;

&lt;p&gt;This is possible if you: &lt;/p&gt;

&lt;p&gt;A: Know the entire code base and your domain inside out. &lt;/p&gt;

&lt;p&gt;or &lt;/p&gt;

&lt;p&gt;B: Have excellent analytics and/or have "internal products"&lt;/p&gt;

&lt;p&gt;Obviously sometimes the above is impossible due to external factors. &lt;/p&gt;

&lt;p&gt;But lets say you can refactor 100 lines of absolute garbage into 50 lines of nicely abstracted method code. &lt;/p&gt;

&lt;p&gt;GitHub will show this as a red PR and for me red PR's are the gold standard of PR's  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kGnnHUDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcdpm9lwez3s6pe1vk0v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kGnnHUDH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vcdpm9lwez3s6pe1vk0v.png" alt="Deleted some code"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Obviously in the above image I added 37 changes, a new feature, yay that's great, new code woo. &lt;/p&gt;

&lt;p&gt;But I also managed to remove 4 lines of code. Doesn't seem like much but those 4 lines of code made that repo a bit less manageable. Scale that up to 400 lines and you have removed a real nice bit of your app. &lt;/p&gt;

&lt;p&gt;Less code = less overhead = more time for the "cool" stuff&lt;/p&gt;

&lt;p&gt;People talk about strangler pattern rebuilds/refactors where you identify core logic in an application and "strangle" down your application by lifting and shifting unnecessary pieces of logic out into microservices or packages until you are left with this really nice small, concise piece of code that is easy to manage and allows you to move really quickly. &lt;/p&gt;

&lt;p&gt;This is just an ideology. Why should it be confined to the constraints of a rebuild. &lt;/p&gt;

&lt;p&gt;If you apply that mindset to your working day or even side projects then you start to attack some of the parts of your repo that keep you up at night. &lt;/p&gt;

&lt;p&gt;Lets say you know for sure that there is an absolute nightmare piece of code inside an API endpoint. It's sole purpose is to transfer data that isn't all that important to a message bus mechanism which is then picked up by a cron scheduled function to place this data off the bus into a database. &lt;/p&gt;

&lt;p&gt;This code keeps you up at night because the cron function keeps erroring out because of network issues between the bus and your cloud provider. &lt;/p&gt;

&lt;p&gt;Why can't you just refactor out that technology and handle the writing of this non important data directly in the API. It's not very cool for your CV but sleep is great for humans. &lt;/p&gt;

&lt;p&gt;The above is probably the worst example ever, but what I am getting at is sometimes the "correct" choice is the most basic choice. &lt;/p&gt;

&lt;p&gt;Because we removed our message bus and our cron function we can also remove our implementation of CQRS in the API. Bye Mediatr, Bye MassTransit. &lt;/p&gt;

&lt;p&gt;We now have one very basic Entity Framework call. Our flow for this non vital data has gone from &lt;/p&gt;

&lt;p&gt;User submits -&amp;gt; API -&amp;gt; DataSubmittedRequest -&amp;gt; -&amp;gt; HandleDataSubmittedRequest -&amp;gt; MassTransit -&amp;gt; MessageBus -&amp;gt; Emit Event -&amp;gt; Cron Function Picks up message -&amp;gt; HandleDataSubmittedRequest -&amp;gt; Entity Framework -&amp;gt; SQL DB &lt;/p&gt;

&lt;p&gt;To&lt;br&gt;
User submits -&amp;gt; API -&amp;gt; Entity Framework -&amp;gt; SQL DB&lt;/p&gt;

&lt;p&gt;Ok sure now we have lost some fault tolerance if the DB write fails the data may be lost but that is the trade off to weigh up sometimes. &lt;/p&gt;

&lt;p&gt;Sometimes allowances have to be made for simplicity but 99% of the time optimistic success will get you very far and your team will be happier as they don't have this overhanging fear of something complicated breaking on a Saturday night when they are having vino with friends. &lt;/p&gt;

&lt;h2&gt;
  
  
  I am 1 developer working on an open source project
&lt;/h2&gt;

&lt;p&gt;If you get GitHub issues in on an open source repo (or you can apply this to your company, it is a little more difficult though) you have 3 options: &lt;/p&gt;

&lt;p&gt;1: Blindly accept the suggestions and implement because if its important to 1 person it must be important to everyone. &lt;/p&gt;

&lt;p&gt;2: Wait for more +1s on this issue and weigh up importance before implementing. &lt;/p&gt;

&lt;p&gt;3: Be very firm with your core goals. Reject anything that does not align with these core goals or directly add value to these core goals. I.E my app does 1 thing and it does it excellently, no I won't add "Stories" to my app &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yrJXVpKw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgwto143f3cqc36cc5hd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yrJXVpKw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lgwto143f3cqc36cc5hd.jpg" alt="Excel stories"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now option 3 probably won't win you many popularity contests but it is the option I would probably choose. If you begin to add features to applications do this with extreme caution. &lt;/p&gt;

&lt;h3&gt;
  
  
  The family hypothesis
&lt;/h3&gt;

&lt;p&gt;Think about your application like a family: &lt;/p&gt;

&lt;p&gt;You have 0 kids, no partner, you rent a really nice apartment in a cool part of town. &lt;/p&gt;

&lt;p&gt;You look after yourself and that is it. Life is easy. You have great hair and enjoy reading and learning new languages. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Todo lo que necesito es vino y un gran libro.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Then you find a partner. A new "feature" in your life. &lt;/p&gt;

&lt;p&gt;Now you share your time with this new feature. &lt;em&gt;I apologise that sounds horrendous and I apologise to my fiancée, you are more than a feature to me&lt;/em&gt; 😂&lt;/p&gt;

&lt;p&gt;You no longer learn new languages because the Duolingo owl "annoys your partner" instead you have both decided that you need to buy a house because you both want to add many new features. &lt;/p&gt;

&lt;p&gt;You now can't drink expensive Chilean wines because you are in a code freeze to be in a great position to add a really nice big feature to your app. &lt;/p&gt;

&lt;p&gt;I hope your still following because I am getting lost 😂&lt;/p&gt;

&lt;p&gt;You buy your first home. A really big one you saved all your money to buy it. &lt;/p&gt;

&lt;p&gt;Everything is great everyone loves your home. It is the best home they have ever seen. &lt;/p&gt;

&lt;p&gt;Then a pipe bursts. You cry a lot. You have to code overtime to fix this issue. &lt;/p&gt;

&lt;p&gt;After several days you have fixed the issue but because you have been so focussed on that you haven't spent any time with your partner so now you have an issue there you need to fix. &lt;/p&gt;

&lt;p&gt;Many "I'm sorry"s later you have resolved your "partner bug" so you decide to add a new feature to celebrate. &lt;/p&gt;

&lt;p&gt;This feature took a lot of time to build. Lets say 9 months or 19.5 sprints. &lt;/p&gt;

&lt;p&gt;Now you have no time to maintain the core application, you begin to lose your hair, you now remember none of the Spanish you learned 8 years ago, your knees hurt a lot, the new young dev that we shall call "Node" scares you at work because you don't speak their language and don't have the time to become their friend even though you wish your application was more like theirs. &lt;/p&gt;

&lt;p&gt;After a little bit of time you add another feature. This time you get through 2 features at once "twinned features" we shall call them. &lt;/p&gt;

&lt;p&gt;You have no idea how you are gonna get through this backlog now. &lt;/p&gt;

&lt;p&gt;Everyone tells you that your application is great now. The best app they know, 5 stars. &lt;/p&gt;

&lt;p&gt;You feel burned out maintaining this massive monolithic application. &lt;/p&gt;

&lt;p&gt;Your "home" feature develops a "hole in roof" bug. This is extremely expensive and has caused the "aaaah theres water everywhere" bug &lt;/p&gt;

&lt;p&gt;You decide to run away to Aruba. You just wanted to build an easy application and enjoy life. &lt;/p&gt;

&lt;p&gt;If only you had rejected that initial pull request. &lt;/p&gt;

&lt;p&gt;The above example is obviously not real life but you see how its very easy to take something simple and low maintenance and turn it into something that seems "daunting and insurmountable"&lt;/p&gt;

&lt;p&gt;Now please whatever you do. DO NOT APPLY DECREMENTAL IMPROVEMENTS TO YOUR FAMILY. You will probably end up in jail. "But your honour, I just opened up a red pr like the random blog post told me to"&lt;/p&gt;

&lt;p&gt;Wow, thats morbid. I apologise. &lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;I waffled a lot there. &lt;/p&gt;

&lt;p&gt;I apologise for that but I was vomiting stuff onto screen. &lt;/p&gt;

&lt;p&gt;This post could probably benefit from some decremental improvements. &lt;/p&gt;

&lt;p&gt;In a nutshell. &lt;/p&gt;

&lt;p&gt;Identify ways you can make your codebases smaller or more easy to maintain. &lt;/p&gt;

&lt;p&gt;It will make your life easier. &lt;/p&gt;

&lt;p&gt;Please delete cautiously. Don't delete the main app logic. &lt;/p&gt;

&lt;p&gt;Somethings cannot be refactored. This is ok you can't win every battle. &lt;/p&gt;

&lt;p&gt;Be cautious when blindly adding new "features" will this cause massive headaches months later for not much return. &lt;/p&gt;

&lt;p&gt;Sometimes it is ok to push back. Fight your corner for why something shouldn't be added. &lt;/p&gt;

&lt;p&gt;If a feature does add real value or it is business critical obviously you can't deny everything, we do still love to write code. &lt;/p&gt;

&lt;p&gt;Great analytics help you to chop down huge code bases by seeing what's needed and what's not. &lt;/p&gt;

&lt;p&gt;It gets me all warm and fuzzy when I delete huge chunks of code.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hall of Fame
&lt;/h1&gt;

&lt;p&gt;Comment your best refactors or biggest project deletions in this post. &lt;/p&gt;

&lt;p&gt;Mines is: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rRRB_hGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09052z8z9tz6qb3cqrzd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rRRB_hGl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/09052z8z9tz6qb3cqrzd.png" alt="BEST PR EVER"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;12,490 lines deleted and 0 new lines added. &lt;/p&gt;

&lt;p&gt;&lt;em&gt;I wept that day.&lt;/em&gt; &lt;strong&gt;TEARS OF JOY&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Anyways I hope this EXTREMELY long post has been of help to someone. &lt;/p&gt;

&lt;p&gt;Thanks, Bye 👋&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>programming</category>
      <category>productivity</category>
      <category>github</category>
    </item>
    <item>
      <title>Knowing when your writing sucks </title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Tue, 13 Apr 2021 09:03:11 +0000</pubDate>
      <link>https://forem.com/granthair5/knowing-when-your-writing-sucks-d3p</link>
      <guid>https://forem.com/granthair5/knowing-when-your-writing-sucks-d3p</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fham3cu591grji20uxw04.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fham3cu591grji20uxw04.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently started a series I called the Bullet Point Series. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/granthair5/bullet-point-series-intro-2hpo"&gt;https://dev.to/granthair5/bullet-point-series-intro-2hpo&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This series was awful. &lt;/p&gt;

&lt;p&gt;The topics of conversation were too vague. &lt;/p&gt;

&lt;p&gt;The bullet point lists were far too long. &lt;/p&gt;

&lt;p&gt;Part 1 came before the intro. &lt;/p&gt;

&lt;p&gt;The whole thing was a mess. &lt;/p&gt;

&lt;p&gt;But I thought I was being really clever. Oh yeah short sharp blog posts is what people want that will really take off I thought. &lt;/p&gt;

&lt;p&gt;I could not have been more wrong. My implementation sucked. My writing style was lazy. It felt robotic and un-personal. That makes it very difficult for people to relate. &lt;/p&gt;

&lt;p&gt;I gave this series a few weeks, no one read it and it fell into the abyss so at that point I had 2 options: &lt;/p&gt;

&lt;p&gt;1: Continue writing in the hope that maybe I'll get lucky and this idea will really take off. &lt;/p&gt;

&lt;p&gt;2: Call it quits and know when to back out and try something new. &lt;/p&gt;

&lt;p&gt;I chose option 2 due to my programming background. Sometimes instead of following Alice down the rabbit hole the best option is to say "Nah forget that" and walk away to the pub. I usually choose this approach when tackling "impossible" bugs in a technique I like to call "next day programming" &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F785%2F1%2A7LzhJXDIubcYIOzWKBRaMA.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmiro.medium.com%2Fmax%2F785%2F1%2A7LzhJXDIubcYIOzWKBRaMA.jpeg" alt="https://miro.medium.com/max/785/1*7LzhJXDIubcYIOzWKBRaMA.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Usually, the next day that "impossible" bug doesn't seem all that impossible but if you continue to bash your head off the wall chances are you won't break down the wall you'll just end up with a headache. &lt;/p&gt;

&lt;p&gt;So, to the handful of people that read the bullet point series I thank you but I am more grateful to those of you who chose not to read it because I feel we learn more from the stuff that doesn't work or the mistakes we make than the glory we can easily become accustomed to. &lt;/p&gt;

&lt;p&gt;Stay tuned for more non bullet point series posts and I hope you all enjoy what is to come. &lt;/p&gt;

&lt;p&gt;Thanks, 👋&lt;/p&gt;

</description>
      <category>writing</category>
    </item>
    <item>
      <title>Bullet point series - Part 2 - Some pretty sweet Visual Studio Extensions I Use</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Fri, 02 Apr 2021 08:53:07 +0000</pubDate>
      <link>https://forem.com/granthair5/bullet-point-series-part-2-some-pretty-sweet-visual-studio-extensions-i-use-4gj5</link>
      <guid>https://forem.com/granthair5/bullet-point-series-part-2-some-pretty-sweet-visual-studio-extensions-i-use-4gj5</guid>
      <description>&lt;h1&gt;
  
  
  Visual Studio
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Viasfora, &lt;a href="https://viasfora.com"&gt;https://viasfora.com&lt;/a&gt;, Rainbow braces, keyword highlighting, I feel that this just makes it easier for me to navigate code bases. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Codemaid, &lt;a href="https://www.codemaid.net"&gt;https://www.codemaid.net&lt;/a&gt;, cleanup on save, cross team formatting practices, this allows me and my team mates to have the same formatting, its just a real sweet timesaver, makes your code pretty too. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resharper, &lt;a href="https://www.jetbrains.com/resharper/"&gt;https://www.jetbrains.com/resharper/&lt;/a&gt;, personally for me the holy grail of extensions, I sometimes feel I don't know C# but rather I know Resharper, it will save you soooooooo much time. Most of its functionality is being rolled into Visual Studio now though. &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Visual Studio Code
&lt;/h1&gt;

&lt;h3&gt;
  
  
  CTRL + SHIFT + P for the win
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Docker, &lt;a href="https://code.visualstudio.com/docs/containers/overview"&gt;https://code.visualstudio.com/docs/containers/overview&lt;/a&gt;, add Dockerfile to workspace is my best friend. &lt;a href="https://code.visualstudio.com/docs/containers/overview#:%7E:text=You%20can%20add%20Docker%20files,add%20them%20to%20your%20workspace"&gt;https://code.visualstudio.com/docs/containers/overview#:~:text=You%20can%20add%20Docker%20files,add%20them%20to%20your%20workspace&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Prettier, &lt;a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode"&gt;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&lt;/a&gt; , make your code pretty &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Live Server, Launch a server for your static sites yes please, no more file path browsing - &lt;a href="https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer"&gt;https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer&lt;/a&gt; &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GitLens - &lt;a href="https://gitlens.amod.io/#features"&gt;https://gitlens.amod.io/#features&lt;/a&gt; , see who did what, when and why in your IDE and also quickly see any changes you have made &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  That's probably enough for now
&lt;/h3&gt;

&lt;p&gt;Have a great weekend, hope this was of help to someone 👋&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Bullet point series - Intro </title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Thu, 25 Mar 2021 11:10:32 +0000</pubDate>
      <link>https://forem.com/granthair5/bullet-point-series-intro-2hpo</link>
      <guid>https://forem.com/granthair5/bullet-point-series-intro-2hpo</guid>
      <description>&lt;p&gt;Hello, &lt;/p&gt;

&lt;p&gt;Firstly excuse my idiocy, I published part one before the intro. &lt;/p&gt;

&lt;p&gt;Damn it Grant, remember the semver training we did. &lt;/p&gt;

&lt;p&gt;I will try keep this brief. &lt;/p&gt;

&lt;p&gt;I am going to try and write some bullet point series posts on a regular basis. These will be &lt;em&gt;hopefully&lt;/em&gt; short and &lt;em&gt;hopefully&lt;/em&gt; easily digestible little nuggets of knowledge. &lt;/p&gt;

&lt;p&gt;Stay Tuned for more code shenanigans &lt;/p&gt;

&lt;p&gt;Bye for now 👋 &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Bullet point series - Part 1 - My PR Best Practices</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Thu, 25 Mar 2021 11:05:46 +0000</pubDate>
      <link>https://forem.com/granthair5/bullet-point-series-part-1-my-pr-best-practices-53if</link>
      <guid>https://forem.com/granthair5/bullet-point-series-part-1-my-pr-best-practices-53if</guid>
      <description>&lt;p&gt;Welcome, to what I hope will be something that I remember to do frequently which is a bullet point series. &lt;/p&gt;

&lt;p&gt;This will be quick to read and hopefully useful little nuggets of knowledge that I may or may not be correct on haha. &lt;/p&gt;

&lt;p&gt;Lets get to it...&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This list is not exhaustive and might differ from your best practices but this is what I tend to try and go with and it seems to have improved our teams PR conversion&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start with great branch names, I like to follow the convention of &lt;code&gt;grant/TICKET-NAME/SHORT-DESCRIPTION&lt;/code&gt; e.g &lt;code&gt;grant/JIRA-1234/Add-Centralized-Caching&lt;/code&gt; this is useful as you can very quickly know who to go to for further information &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Make smaller pull requests, think about it how many of us would read in fine detail a 300 files changed PR &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Give yourself an early chance of finding any crap by self reviewing. You will not believe how much stuff I've found doing this. Add PR comments on anything you think might be confusing to someone else or the reasoning behind a decision. Draft PR's are your friend for this. &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Use descriptive and declarative commit messages the practice I use is to in my mind prefix all commit messages with "If applied this commit will..." This gives the reviewer a recipe for your PR and they can see how you got to the point you are at now. &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;If you PR is for a bug fix where applicable add bug trap testing, this is a test around your bug fix. This allows the reviewer to see in terms of code what went wrong, what you did to fix it and also what you have done to test it, It also means that in future if your code is modified in any way the bug trap test may fail and prevent anyone introducing that same bug again. &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Use a PR template, knowing exactly where to go in a PR description every single time to get the information that you need will save you so much time long term trying to sift through a paragraph. I usually use something like this &lt;a href="https://gist.github.com/GrantHair5/97b5564131376888cc45c4c35d68a3bc"&gt;https://gist.github.com/GrantHair5/97b5564131376888cc45c4c35d68a3bc&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;If it is a visual change please add a screenshot or GIF it helps the reviewer so much with understanding your change. &lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Please spend the time to write a good PR description put yourself in others shoes. If you spend 5 minutes now that saves every reviewer 10 minutes and you have 3 reviewers there's a half hour saving right off the bat. "Fix broke stuff" doesn't cut it anymore haha&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Don't treat PR comments as a blocker, treat them as a way to collaboratively better your codebase, you might have missed something, PR's should be a safe space, if something is worth doing and someone else has put the effort into putting a change request in give it the credit it is due and talk it through with someone.&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Don't be scared to tell someone in a PR that they've done a great job, go crazy with emojis and GIFs it makes your repo a happier place and might give someone a little boost for the day. Be Kind to people.
&lt;/li&gt;
&lt;/ul&gt;




&lt;ul&gt;
&lt;li&gt;Red PR's are the best PR's, I call this decremental improvements and I'll write a little post about this later on but basically delete pointless stuff, we can always recover some comment that was in a code base. SCM LYF ❤️ &lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;I'll call time on this there, the bullet points got kinda lengthy but hopefully something in there will be of help to someone.&lt;/p&gt;

&lt;p&gt;If you have any best practices you usually follow shoot them in the comments below I am always looking to improve processes. &lt;/p&gt;

&lt;h2&gt;
  
  
  Bye for now 👋
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/TgV7fAvYIZMHOed0Rg/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/TgV7fAvYIZMHOed0Rg/giphy.gif" alt="https://media.giphy.com/media/TgV7fAvYIZMHOed0Rg/giphy.gif"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>tutorial</category>
      <category>productivity</category>
      <category>csharp</category>
    </item>
    <item>
      <title>Any other yerba loving devs out there? </title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Thu, 18 Mar 2021 09:19:32 +0000</pubDate>
      <link>https://forem.com/granthair5/any-other-yerba-loving-devs-out-there-2h7</link>
      <guid>https://forem.com/granthair5/any-other-yerba-loving-devs-out-there-2h7</guid>
      <description>&lt;p&gt;I got into drinking Yerba a few years ago after a fellow developer introduced me after his travels of South America check him out here &lt;a href="https://backpackerdeveloper.com/" rel="noopener noreferrer"&gt;https://backpackerdeveloper.com/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I find that Yerba Mate helps me stay focused for longer than coffee and I just generally enjoy the taste more.&lt;/p&gt;

&lt;p&gt;It also looks real cool and makes people wonder "what is that dude drinking" &lt;/p&gt;

&lt;p&gt;There are also some proven and some unproven health benefits &lt;a href="https://www.healthline.com/nutrition/8-benefits-of-yerba-mate" rel="noopener noreferrer"&gt;https://www.healthline.com/nutrition/8-benefits-of-yerba-mate&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Yerba subculture is also something that fascinated me and I have learned so much and have passed on some knowledge and tricks to colleagues looking to take up the fantastically social dance that is a ronda de yerba, we even have a Teams channel dedicated to that now.   &lt;/p&gt;

&lt;p&gt;I am currently enjoying Rosamonte (IT MUST BE ESPECIAL) and Cruz De Malta (my first time trying Cruz) &lt;/p&gt;

&lt;p&gt;&lt;em&gt;excuse the messy desk, I like creative chaos&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc69416g86xj4nmvw56u.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhc69416g86xj4nmvw56u.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Does anyone have a favourite Yerba they like to drink while coding or anything they could recommend? &lt;/p&gt;

&lt;p&gt;For anyone interested I get my Yerba Mate from here &lt;a href="https://urushop.co.uk/" rel="noopener noreferrer"&gt;https://urushop.co.uk/&lt;/a&gt; it is a great place to get Yerba in the UK &lt;/p&gt;

&lt;p&gt;My setup is as follows: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gourd/Cup - &lt;a href="https://urushop.co.uk/shop/yerba-mate-accessories/mates-gourds/thermal-stainless-steel-mate-cup/" rel="noopener noreferrer"&gt;https://urushop.co.uk/shop/yerba-mate-accessories/mates-gourds/thermal-stainless-steel-mate-cup/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Bomba/Bombilla (I like bomba cause the wider mouth gets more flavourtown in my mouth) - &lt;a href="https://urushop.co.uk/shop/yerba-mate-accessories/bombillas-straws/stainless-steel-brazilian-bomba/" rel="noopener noreferrer"&gt;https://urushop.co.uk/shop/yerba-mate-accessories/bombillas-straws/stainless-steel-brazilian-bomba/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Mate - &lt;a href="https://urushop.co.uk/shop/yerba-mate-from-south-america/1kg/yerba-mate-cruz-de-malta-1kg/" rel="noopener noreferrer"&gt;https://urushop.co.uk/shop/yerba-mate-from-south-america/1kg/yerba-mate-cruz-de-malta-1kg/&lt;/a&gt; or &lt;a href="https://urushop.co.uk/shop/yerba-mate-from-south-america/1kg/yerba-mate-rosamonte-especial-1kg/" rel="noopener noreferrer"&gt;https://urushop.co.uk/shop/yerba-mate-from-south-america/1kg/yerba-mate-rosamonte-especial-1kg/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Flask aka my love HÄLSA - &lt;a href="https://www.ikea.com/gb/en/p/haelsa-steel-vacuum-flask-blue-40450637/" rel="noopener noreferrer"&gt;https://www.ikea.com/gb/en/p/haelsa-steel-vacuum-flask-blue-40450637/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Look forward to any suggestions 👋&lt;/p&gt;

&lt;h1&gt;
  
  
  🧉
&lt;/h1&gt;

</description>
      <category>discuss</category>
      <category>watercooler</category>
      <category>yerba</category>
      <category>productivity</category>
    </item>
    <item>
      <title>How I decompress as a developer</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Wed, 17 Mar 2021 14:30:52 +0000</pubDate>
      <link>https://forem.com/granthair5/how-i-decompress-as-a-developer-18h9</link>
      <guid>https://forem.com/granthair5/how-i-decompress-as-a-developer-18h9</guid>
      <description>&lt;h2&gt;
  
  
  tl;dr;
&lt;/h2&gt;

&lt;p&gt;Care less, Buy a dog, Go to the forest and shout at trees&lt;/p&gt;




&lt;p&gt;As a developer it is very easy to become swept up in problem solving, imposter syndrome, comparing ourselves to those around us, office drama, overwhelming deadlines, obviously Covid-19 and how that has affected our lives and so much more. &lt;/p&gt;

&lt;p&gt;I think for some people that are developers and this is a generalisation that some may not feel, we are viewed as people that have an extremely easy lifestyle and we just play table tennis 95% of the day, watch YouTube 4% of the day and make buttons on screens the remaining 1% of the day then we get to finish early and go grab some sushi with our other dev friends. &lt;/p&gt;

&lt;p&gt;This doesn't usually leave us much room to complain about some deadline that we are scared we might not meet or that one runtime bug that you just can't squash or that crushing feeling that you have no clue what you are doing 99% of the time and you feel like you spend all your time copy pasting the code of smarter people from Stack Overflow and when you reach a point where that doesn't work and you have to dust off the cobwebs and flex your own brain it can't seem to get past 1st gear. &lt;/p&gt;

&lt;p&gt;I think as we are usually painted as highly intelligent people that can solve complex problems like putting a button on a screen and making it clicky click, people often assume we have all the answers in our big beefy brains and will never have that feeling of inadequacy but throughout my career I can remember vividly all of these times whereas I struggle to remember my "rockstar" moments where I absolutely crushed some issue or made something that saved a colleague a bunch of time. &lt;/p&gt;

&lt;p&gt;Then I remember that this is extremely common for most people regardless of their career path. &lt;/p&gt;

&lt;p&gt;Do you remember that time you ripped your shorts in High School in front of the whole class, I guarantee you do but I guarantee that hardly anyone else in that class does. This is because as creatures we always store these traumatic events in our mind and other people don't have the space to remember your traumatic events because they have their own crap going on up there. &lt;/p&gt;

&lt;p&gt;So the next time you say something that you think is "stupid" in a meeting full of people that you assume are better than you or commit some code that you think is the worst code ever or get asked a question that you don't know the answer to just remember that although it may be painful now after the moment has passed there is a high chance that no one but yourself will look back on that moment. The important thing in that moment is that you use it as an experience to learn something. &lt;/p&gt;

&lt;p&gt;Remember when you were a kid and you were learning to walk, remember how many times you fell over (probably not because you were an infant but you get my drift) that traumatic experience is what allowed you to learn to walk, so if the same very basic logic is applied to your professional development and every time you make a mistake, do something outside your comfort zone, take a risk that doesn't pay off or just do something that 5 minutes later you are like "Why did I commit that, oh no people will think I am a moron and I am sure to get caught out as a fraud" (yes I've been there) then please try and ask yourself these questions: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If I did this again, knowing what I know now, what would I do differently? &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did the world end because of what I did? &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did I do what I did because I thought it was the right thing to do at that time? &lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Did the world end because of what I did? &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Is probably the most important question I ask myself whenever I make a mistake. &lt;/p&gt;

&lt;p&gt;It is very easy to get yourself all worked up because you committed something like the following&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;thisBoolShouldBeFalse&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;DoSomethingThatShouldHappenWhenBoolIsTrue&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;DoSomethingThatShouldHappenWhenBoolIsFalse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now unless the code above is the main logic behind some kind of nuclear device then the world probably didn't end because you committed that and it made it through PR and then out to users for a day until it was highlighted. &lt;/p&gt;

&lt;p&gt;Hey we all make mistakes and sometimes as "Developers", "Engineers", "Evangelists" or even "JavaScript Ninjas" we don't always like to show our flaws because often our imposter syndrome is so crushing that we feel even one tiny mistake will push us off our elitist pedestal that we have placed our self on, the best developers that I have worked with are the ones who will make a mistake and then find it and be like "Haha look at this crap that I wrote here is what I did to fix this..." &lt;/p&gt;

&lt;p&gt;If you adopt the above approach then I feel like a lot of weight will be lifted from your shoulders because honestly the majority of us developers even though we may be scary on Stack Overflow are really nice people at heart and we just want to see those around us succeed. &lt;/p&gt;

&lt;p&gt;It is ok to feel overwhelmed. &lt;/p&gt;

&lt;p&gt;It is ok to feel scared, I feel scared when people talk about stuff at a very technical level because my mind works best at "beep boop I make computer go now" and large architecture diagrams, "lets talk about algorithms", "what design practice did you use for X?", acronyms for acronyms sake and Big O scare me a lot and I used to pretend that I knew all this stuff until I asked one day "What does that mean?" and the dev answered "I don't know either haha" &lt;/p&gt;

&lt;p&gt;It is ok to know what you know and also what you don't know but it is also ok to not know what you don't know, our environment as computer wielding ninjas is always changing and it's ok to not be super up to date with stuff that's why the internet exists we live in a time where any information you could ever want is literally available in a TikTok video, as a meme or as a blog post so cramming books into your brain might not work for you, that doesn't make you worse that the other dev that devours O'Reilly like they are California Rolls (circle of life it all begins and ends with sushi)  &lt;/p&gt;

&lt;p&gt;The main thing to remember is that computers are just rocks that we tricked into thinking and if at the end of the day the world is still spinning your code can't have been as bad as you thought it was. &lt;/p&gt;

&lt;p&gt;Find your people that you can talk to, I often use &lt;a href="https://devrant.com" rel="noopener noreferrer"&gt;https://devrant.com&lt;/a&gt; to rant about code and other stuff that happens that were I to talk to a non developer about they might just not get it, sometimes you just need to shout about stuff and get someone that is like "I know right". &lt;/p&gt;

&lt;h3&gt;
  
  
  Ok, nice Ted Talk get to the good bits.
&lt;/h3&gt;

&lt;p&gt;As I live in Scotland, a mostly beautiful country, and because I am very much not a city boy (I grew up in mostly farm lands where there are very little computer based jobs, check it out here if you are interested &lt;a href="https://goo.gl/maps/m1FQbhnY3KBu4W1e7" rel="noopener noreferrer"&gt;https://goo.gl/maps/m1FQbhnY3KBu4W1e7&lt;/a&gt; &amp;amp; &lt;a href="https://en.wikipedia.org/wiki/Dumfries" rel="noopener noreferrer"&gt;https://en.wikipedia.org/wiki/Dumfries&lt;/a&gt;), I like to escape to the country, now that has been difficult given the current restrictions so I have had to do some digging around what is available where I live now, this in itself is a joy and I have a list of places to go to now.&lt;/p&gt;

&lt;p&gt;I usually just go to Google Maps, turn on satellite view and try and find anything green or beachy that I can drive to under the current restrictions. &lt;/p&gt;

&lt;p&gt;I have been able to find some pretty sweet forests that are usually fairly deserted and as I got a lockdown puppy (a black lab named Luna) I like to take her walks through the quiet wooded areas, up some hills or over large moorland. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tsjmmfy01q3a4hnqqjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1tsjmmfy01q3a4hnqqjq.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg85gep0nsepasqif0qf2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg85gep0nsepasqif0qf2.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sr6jlze11e3dhi9gy3h.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sr6jlze11e3dhi9gy3h.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This gives me the time that I need away from screens and I can truly feel disconnected for a period of time. After the working day is done I make sure to put the lid of my laptop down and try take at least 30 minutes away from people and screens, this gives me the time I need to become centred again. If you can spin around 360 and not see another person then even better it is time for some soul cleansing shouting. &lt;/p&gt;

&lt;p&gt;I feel like that's enough clichés for one blog post but to conclude: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Find your people that you can have open honest discussions with&lt;/li&gt;
&lt;li&gt;No matter how small or insignificant you feel your problem is it is always best when shared often philosophical ruminations will only eat away at you and like the avalanche that begun with a snowflake it can very easily overwhelm you &lt;/li&gt;
&lt;li&gt;Never apologise for asking what you feel are "dumb" questions, if it is important to you it should be important enough for those around you&lt;/li&gt;
&lt;li&gt;Don't let your mistakes eat away at you, 99% of the time you will be part of a team of developers that are there to catch you if you fall, use them and learn from your mistakes because we all make them&lt;/li&gt;
&lt;li&gt;Imposter syndrome happens to even the most seasoned developers, there will always be stuff that you don't know, you are not an Encyclopaedia of knowledge, you are an unfinished autobiography. &lt;/li&gt;
&lt;li&gt;If it all gets to much shouting at trees can help&lt;/li&gt;
&lt;li&gt;Care less about what other people think because they are probably caring too much about what you think of them to even care about what they think about you. &lt;/li&gt;
&lt;li&gt;Sometimes the oldest clichés are the most applicable to blog posts. That's why pencils have erasers, a problem shared is a problem halved, sometimes mistakes that you think you've made can be perceived as moments of genius from others viewpoint, fake it till you make it etc&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If anyone would like to chat about any of the above or any feelings they have around imposter syndrome etc then either drop a comment below or fire a social media message at me, links should be in my bio because we are all in this together and some of the stuff that you are feeling right now high chance is I will have felt it to or are currently going through it. &lt;/p&gt;

&lt;p&gt;The above is anecdotal from my experience as mid level engineer and is in no way targeted so I hope it can be taken in the way it is supposed to be taken, a light-hearted jab at some of my misfortunes and shortcomings to take the edge of an extremely sensitive subject for most and hopefully break down some walls or anxious feelings that some may have to be the catalyst for a discussion point, if we all open ourselves up to the idea of making ourselves look "stupid" then it hopefully breaks the feeling that it is such a bad thing to do. &lt;/p&gt;

&lt;p&gt;If you would like to see more random pictures from my adventures I usually post stuff on my Instagram here: &lt;a href="http://instagram.com/granthair96" rel="noopener noreferrer"&gt;http://instagram.com/granthair96&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I will also hopefully follow this up with a "Here's the stuff I don't know in 2021" post similar to Dan Abramovs "Things I Don’t Know as of 2018"&lt;/p&gt;

&lt;p&gt;&lt;a href="https://overreacted.io/things-i-dont-know-as-of-2018/" rel="noopener noreferrer"&gt;https://overreacted.io/things-i-dont-know-as-of-2018/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That article really opened my eyes and made me realise that because I don't know how to convert binary to hex, because I don't fully understand what a strategy pattern is or because I don't understand how routers work and now I'm too scared to ask it doesn't make me less of a developer. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1udwzkypt1rjwu9hrd2n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1udwzkypt1rjwu9hrd2n.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks, I hope this was of help for some 👋&lt;/p&gt;

</description>
      <category>mentalhealth</category>
      <category>watercooler</category>
      <category>discuss</category>
    </item>
    <item>
      <title>A couple ways I test my .NET APIs </title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Fri, 26 Feb 2021 16:16:02 +0000</pubDate>
      <link>https://forem.com/granthair5/a-couple-ways-i-test-my-net-apis-omk</link>
      <guid>https://forem.com/granthair5/a-couple-ways-i-test-my-net-apis-omk</guid>
      <description>&lt;p&gt;Recently I have undertaken some work that required either building a whole new API or regression testing another API. &lt;/p&gt;

&lt;p&gt;Through that experience I used 3 techniques to help build my confidence that what I was building actually worked, these are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unit Tests &lt;/li&gt;
&lt;li&gt;In Memory API Tests with &lt;code&gt;WebApplicationFactory&amp;lt;TEntryPoint&amp;gt;&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;Newman Tests &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I will assume that everyone is familiar with unit tests in C# but just a quick note that my favourite framework is XUnit. I really enjoy the simplicity that it brings and allows me to get up and running super quickly. &lt;/p&gt;

&lt;h2&gt;
  
  
  In Memory API Tests with &lt;code&gt;WebApplicationFactory&amp;lt;TEntryPoint&amp;gt;&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;tl;dr; &lt;/p&gt;

&lt;p&gt;Check out this GitHub repo&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GrantHair5/DotNetApiInMemoryTests"&gt;https://github.com/GrantHair5/DotNetApiInMemoryTests&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;It has some pretty nice examples at a &lt;strong&gt;very&lt;/strong&gt; basic level I'm taking lets get some fruit from a basket kinda stuff. &lt;/p&gt;

&lt;h3&gt;
  
  
  How?
&lt;/h3&gt;

&lt;p&gt;The MVP of this test is &lt;code&gt;WebApplicationFactory&amp;lt;TEntryPoint&amp;gt;&lt;/code&gt; it allows me to run an in-memory version of my API using &lt;code&gt;TestServer&lt;/code&gt; this gives me access to a &lt;code&gt;HttpClient&lt;/code&gt; and also my actual API. I can then send HTTP calls to my API as I would do in real life and assert the responses. &lt;/p&gt;

&lt;p&gt;This is a great time to plug one of my favourite NuGet packages, FluentAssertions. It gives you the ability to assert test cases using plain English style language and makes complex test assertions a breeze. &lt;/p&gt;

&lt;p&gt;Anyways, &lt;/p&gt;

&lt;p&gt;To use &lt;code&gt;WebApplicationFactory&amp;lt;TEntryPoint&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You would write something like the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApiWebApplicationFactory&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;WebApplicationFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Startup&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConfigureWebHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IWebHostBuilder&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureTestServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IFruitBasket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;StubbedFruitBasket&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ApiWebApplicationFactory&lt;/code&gt; will become your new best friend.&lt;/p&gt;

&lt;p&gt;Basically this is allowing us to override the default implementation of &lt;code&gt;IFruitBasket&lt;/code&gt; with our new &lt;code&gt;StubbedFruitBasket&lt;/code&gt; perfect for testing stuff with. &lt;/p&gt;

&lt;p&gt;Then I inherit &lt;code&gt;ApiWebApplicationFactory&lt;/code&gt; into my next best friend &lt;code&gt;IntegrationTestBase&lt;/code&gt; which I use across each of my integration tests to get access to that sweet sweet in memory API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegrationTestBase&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IClassFixture&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ApiWebApplicationFactory&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ApiWebApplicationFactory&lt;/span&gt; &lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;HttpClient&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;IntegrationTestBase&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiWebApplicationFactory&lt;/span&gt; &lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;Factory&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then my tests look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt; &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;FruitApiShould&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;IntegrationTestBase&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;FruitApiShould&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ApiWebApplicationFactory&lt;/span&gt; &lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fixture&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Return_Two_Fruits_From_Stubbed_Basket&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/Fruit/Basket"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;basket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;basket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;HaveCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I want to override the stubbed implementation of my &lt;code&gt;IFruitBasket&lt;/code&gt; I can do this by using my &lt;code&gt;ApiWebApplicationFactory Factory&lt;/code&gt; from &lt;code&gt;IntegrationTestBase&lt;/code&gt; to call &lt;code&gt;Factory.WithWebHostBuilder()&lt;/code&gt; like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Fact&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;Return_Four_Fruits_From_Real_Basket_Overriden_By_With_Web_Host_Builder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// WithWebHostBuilder will allow us to override the base Client with any new services that we require.&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Factory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WithWebHostBuilder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConfigureServices&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddTransient&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IFruitBasket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FruitBasket&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;
            &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;CreateClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/api/Fruit/Basket"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;Be&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;HttpStatusCode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;basket&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;JsonConvert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeserializeObject&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;Fruit&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
            &lt;span class="n"&gt;basket&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Should&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;HaveCount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simple right 👍&lt;/p&gt;

&lt;h2&gt;
  
  
  Some things to note
&lt;/h2&gt;

&lt;p&gt;1: &lt;code&gt;services.ConfigureTestServices()&lt;/code&gt; is called after &lt;code&gt;services.ConfigureServices()&lt;/code&gt; in the natural pipeline allowing us to override implementations or configuration or databases etc. &lt;/p&gt;

&lt;p&gt;2: The above is obviously not a real life implementation and should be used as a guide, any terrible code is not a reflection of my real life performance 😂 &lt;/p&gt;

&lt;h2&gt;
  
  
  Newman Tests
&lt;/h2&gt;

&lt;p&gt;I have probably already bored you to death so I'll just drop a tl;dr; here &lt;/p&gt;

&lt;h3&gt;
  
  
  tl;dr;
&lt;/h3&gt;

&lt;p&gt;Newman is an NPM package&lt;/p&gt;

&lt;p&gt;It allows you to run many http requests from a postman collection &lt;/p&gt;

&lt;p&gt;You can write JavaScripty style tests against your collections, for me these were: &lt;/p&gt;

&lt;p&gt;Is my status code 200 &lt;/p&gt;

&lt;p&gt;Is my JSON response what I expect it to be &lt;/p&gt;

&lt;p&gt;It is super cool and helpful. &lt;/p&gt;

&lt;p&gt;It saved me so much time as I didn't have to hit over 120 endpoints individually. &lt;/p&gt;

&lt;p&gt;Check out this link for more info: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/"&gt;https://learning.postman.com/docs/running-collections/using-newman-cli/command-line-integration-with-newman/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Hope this was of help&lt;/p&gt;

&lt;p&gt;See Ya 👋&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>testing</category>
    </item>
    <item>
      <title>The only way you should be handling exceptions in C#</title>
      <dc:creator>Grant Hair</dc:creator>
      <pubDate>Wed, 24 Feb 2021 12:34:13 +0000</pubDate>
      <link>https://forem.com/granthair5/the-only-way-you-should-be-handling-exceptions-in-c-4gpo</link>
      <guid>https://forem.com/granthair5/the-only-way-you-should-be-handling-exceptions-in-c-4gpo</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XerLt-bs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x10pouxbj3pdo9dt2b91.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XerLt-bs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/x10pouxbj3pdo9dt2b91.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Enjoy ☀️
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://gist.github.com/GrantHair5/88a9f902d287cc5efc40cd4c63c81125"&gt;https://gist.github.com/GrantHair5/88a9f902d287cc5efc40cd4c63c81125&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;or if you enjoy a fiddle (that sounded weird but were rolling with it)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dotnetfiddle.net/E0JdC1"&gt;https://dotnetfiddle.net/E0JdC1&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
    </item>
  </channel>
</rss>
