<?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: MichaelFack1</title>
    <description>The latest articles on Forem by MichaelFack1 (@michaelfack).</description>
    <link>https://forem.com/michaelfack</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%2F806603%2Febb6b2f5-ec9e-4418-bf33-f5fe593d15ab.png</url>
      <title>Forem: MichaelFack1</title>
      <link>https://forem.com/michaelfack</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/michaelfack"/>
    <language>en</language>
    <item>
      <title>Writing Good Tests (Part 2) - What Makes a Test Good</title>
      <dc:creator>MichaelFack1</dc:creator>
      <pubDate>Mon, 14 Mar 2022 12:05:38 +0000</pubDate>
      <link>https://forem.com/itminds/writing-good-tests-part-2-what-makes-a-test-good-289d</link>
      <guid>https://forem.com/itminds/writing-good-tests-part-2-what-makes-a-test-good-289d</guid>
      <description>&lt;p&gt;In the previous post, I ranted about what &lt;em&gt;not&lt;/em&gt; to do when writing tests and how to detect a bad test. In this post, I'm going to attempt to provide some pointers as to how you go about writing good tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a test good?
&lt;/h2&gt;

&lt;p&gt;Just like good code is a bit hard to pin down, so is a good test, but you will not be in any doubt when you read a good test, especially if it fails as it achieves its purpose - it will tell you exactly what went wrong and what needs fixing!&lt;/p&gt;

&lt;p&gt;Let us demonstrate this by having a look at a failure. Consider our first example &lt;code&gt;Test1&lt;/code&gt;. If it fails, you will be presented with text similar to "UnitTest1.Test1 failed: false != true". &lt;em&gt;"This is true"&lt;/em&gt; said the tautalog. Instead consider the following test:&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;readonly&lt;/span&gt; &lt;span class="n"&gt;CmsService&lt;/span&gt; &lt;span class="n"&gt;subject&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;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;ICmsReadRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;readRepoMock&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;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;ICmsWriteRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;writeRepoMock&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;CmsServiceUnitTest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;writeRepoMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ICmsWriteRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;readRepoMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ICmsReadRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="n"&gt;subject&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;CmsService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Of&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;CmsService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;(),&lt;/span&gt; &lt;span class="n"&gt;readRepoMock&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;writeRepoMock&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="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;...&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;InvalidKeyDuoInvalidChar&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"An invalid key e&amp;gt;&amp;lt;ample"&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;ReadSectionAsync_InvalidCharKey_ThrowsInvalidCharException&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Arrange&lt;/span&gt;
    &lt;span class="nf"&gt;DefaultSetup&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;taskExpectedToThrow&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;subject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadSectionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InvalidKeyDuoInvalidChar&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Assert&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ThrowsAsync&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;InvalidCharException&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;  &lt;span class="n"&gt;taskExpectedToThrow&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;And the following message &lt;br&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%2F987p6vqnwlc2yfqypsg6.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%2F987p6vqnwlc2yfqypsg6.png" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
This tells you that an &lt;code&gt;InvalidCharException&lt;/code&gt; was expected from the &lt;code&gt;CmsService&lt;/code&gt; when calling &lt;code&gt;ReadSectionAsync&lt;/code&gt;, with a key containing an invalid &lt;code&gt;char&lt;/code&gt;. Now, in this case, a few things could have gone wrong. Perhaps we no longer indicate failure to read with exceptions anymore but use the optional pattern instead, or perhaps we forgot to validate the key. I happen to know that we did not switch to the optional pattern which means the latter is true. Whoopsie.&lt;/p&gt;

&lt;p&gt;All of this, I was able to infer from the test case, thus saving me tons of time I could have wasted Bughunting.&lt;/p&gt;

&lt;p&gt;Furthermore, with a nice test coverage % and the most important and most common features under test, I can rest easy at night knowing my software is functional and not just a stinking heap of-. And, I also save time not manually testing which is time well spent in my opinion.&lt;/p&gt;

&lt;h2&gt;
  
  
  The purpose of a test
&lt;/h2&gt;

&lt;p&gt;Without getting too metatheoretical, I would like to briefly discuss what "the purpose" of a test is, explicitly.&lt;/p&gt;

&lt;p&gt;Say, I have a CMS service I want to test. I have some assumptions with respect to its functionality: It should be safe, practical and efficient. Moreover, say, that to be safe, it shouldn't allow all characters but only a specific subset of characters. Now I want to assert that my CmsService doesn't accept any of the illegal characters. Therefore, I write a unit test of which the purpose is to verify this. It initially fails, but after the introduction of a guard-clause, the test passes and I &lt;em&gt;believe&lt;/em&gt; everything is good. The next day, I want to demonstrate this new behavior to my team, and I open the webpage utilizing the service to update the entries. You input an illegal character, press save and ... It saves!&lt;br&gt;
You dive in to the database to discover a strange sequence of letters prefixed with an &lt;code&gt;&amp;amp;&lt;/code&gt;. Somewhere there was a mismatch between the purpose of the test and the actual test.&lt;/p&gt;

&lt;p&gt;This is obviously a very constructed example, but my point is that the test did not fulfill its purpose. A more appropriate test to write when verifying that the system does not accept invalid characters in its frontend is a frontend test, or perhaps a system test. Had I written a frontend test, I might have discovered that some middleware translates user input into safe strings that cannot be utilized in injection attacks. Had I written a system test, I might have discovered that the underlying CMS API has protection. It would have been more appropriate to write a unit test when asserting unit behavior, such as "I expect the &lt;code&gt;CmsService&lt;/code&gt; to call the &lt;code&gt;CmsApiClient&lt;/code&gt; when &lt;code&gt;GetSectionAsync&lt;/code&gt; is called".&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In the first post we discussed that if a test is not informative and exact, simple, timely and repeatable, then it's a bad test. In this post, we expanded on the concept of a test being good by discussing what a test needs to do; achieve its purpose of validating an assertion that we make about how some part of, or the whole, system works.&lt;/p&gt;

&lt;p&gt;We also determined that this can only be done when we know what the assertion is and create a test based on this. In particular, we want the type of the test to match the layer of abstraction. If only there was some literature on the different kinds tests types paradigms that exist...&lt;/p&gt;

&lt;h2&gt;
  
  
  Remark
&lt;/h2&gt;

&lt;p&gt;If you have any questions, disagree with anything, or if you would like something added to this blog post - leave a comment!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;p&gt;My personal experience,&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices&lt;/a&gt;&lt;br&gt;
&lt;a href="https://martinfowler.com/bliki/GivenWhenThen.html" rel="noopener noreferrer"&gt;https://martinfowler.com/bliki/GivenWhenThen.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29" rel="noopener noreferrer"&gt;https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29&lt;/a&gt; (Clean Code by Robert C. Martin summary)&lt;br&gt;
&lt;a href="https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0&lt;/a&gt;&lt;/p&gt;

</description>
      <category>testing</category>
    </item>
    <item>
      <title>Writing Good Tests (Part 1) - What Makes a Test Bad</title>
      <dc:creator>MichaelFack1</dc:creator>
      <pubDate>Thu, 03 Mar 2022 10:51:23 +0000</pubDate>
      <link>https://forem.com/itminds/writing-good-tests-part-1-what-makes-a-test-bad-4gfd</link>
      <guid>https://forem.com/itminds/writing-good-tests-part-1-what-makes-a-test-bad-4gfd</guid>
      <description>&lt;p&gt;Unless you're some kind of demi-god, I believe you too have tried writing some new fresh code that didn't execute as you expected at first. Perhaps you forgot a guard-clause, some underlying dependency didn't behave as anticipated or, for some other reason, a bug was introduced to your precious code. What is more important (at least with regards to this blog post) is that you discovered this by compiling the code, running the software and seeing it fail.&lt;/p&gt;

&lt;p&gt;In this blogpost, I hope to indoctrinate you into believing in the higher powers; automated testing!&lt;/p&gt;

&lt;h1&gt;
  
  
  Don't just write tests
&lt;/h1&gt;

&lt;p&gt;Let me know if you've ever been in this situation before; you've just opened your favorite IDE to work on a large (and old) project, you see the infamous area of the project aptly named "Tests", and you shudder a little bit?&lt;br&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%2Fzwywxviymhwquw008mft.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%2Fzwywxviymhwquw008mft.png" alt="Example of folder named "&gt;&lt;/a&gt;&lt;br&gt;
I have, and I can tell you why I shuddered - I knew I was the one delegated the tasks of fixing tests that did not succeed anymore. I was the designated Bughunter (trademark pending), and I knew a bug could take days to resolve, even for my more experienced coworkers who had been working on the project for years.&lt;/p&gt;

&lt;p&gt;You know why? The tests were bad!&lt;/p&gt;

&lt;h2&gt;
  
  
  What makes a test bad?
&lt;/h2&gt;

&lt;p&gt;Just like a bowl of cereal, a lot of things can make a test bad, and it is not always clear why a test has gone bad. However, once you've had a spoonful of it - you know!&lt;/p&gt;

&lt;p&gt;In this short series, I am first going to supply you with a non-exhaustive list of things to check for when suspecting a test of being bad, and then later on in the series, I will discuss how to write good tests.&lt;/p&gt;

&lt;p&gt;I just happened to have a &lt;code&gt;CmsService&lt;/code&gt; lying around which implements a Read/Write access string mapping in a database and that I need to test, so, below I'll use it as an example of how NOT to write a test.&lt;/p&gt;

&lt;p&gt;Try to spot a few things you find obscene in the following .NET code segment.&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;UnitTest1&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;Theory&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;MemberData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;nameof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;TestData&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;Test1&lt;/span&gt;&lt;span class="p"&gt;(&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;Tuple&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CmsDbEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;expected&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;boolResult&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;repoMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ICmsWriteRepository&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;dbContextMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CmsDbContext&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;repo&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;CmsRepository&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;dbContextMock&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&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;CmsService&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;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;CreateLogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CmsService&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(),&lt;/span&gt; &lt;span class="n"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;repoMock&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;entriesMock&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;Mock&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;DbSet&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;CmsDbEntry&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&amp;gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;entriesMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ReturnsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;dbContextMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Entries&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Returns&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;entriesMock&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="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;result&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;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadSectionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"some arbitrary constant"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ignoreCase&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="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boolResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;repoMock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"some arbitrary constant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Content"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;ReturnsAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boolResult&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;boolResult0&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;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteSectionAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"some arbitrary constant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Content"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Assert&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Equal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;boolResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;boolResult0&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="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;[][]&lt;/span&gt; &lt;span class="n"&gt;TestData&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="kt"&gt;object&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="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here's a few things I like to pay attention to:&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the test readable?
&lt;/h3&gt;

&lt;p&gt;At a quick glance, the test should convey what is being tested. If it fails to convey what is being tested, at best, it becomes harder to update as the target code changes, at worst, it can sabotage development as it misleads the developer.&lt;/p&gt;

&lt;p&gt;If you cannot discern what a test tests, how can you know if it is correct? A test which you cannot tell whether is correct or not because you cannot discern its purpose or meaning adds no value. &lt;strong&gt;You are better off without it&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is the test well named?
&lt;/h3&gt;

&lt;p&gt;A well-named test might convey the entire purpose of a test, much like how a well-named method conveys its functionality.&lt;/p&gt;

&lt;p&gt;Formatting test names in a consistent way helps conveying  purpose. Additionally, in conjunction with other tests, well-named tests can actually help you pinpoint exactly where you should look for bugs.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I personally use the &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices#naming-your-tests" rel="noopener noreferrer"&gt;{method}_{condition}_{result}&lt;/a&gt;.
```c#
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;public class CmsServiceUnitTests {&lt;br&gt;
  [Fact]&lt;br&gt;
  public async Task ReadSectionAsync_ValidKeyOfExistingEntry_ReturnsEntry() {&lt;br&gt;
    ...&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- Other naming conventions also exist - I can recommend the [{Given}\_{When}\_{Then}](https://martinfowler.com/bliki/GivenWhenThen.html) format since user stories can be formulated in this format as well.
```c#


public class CmsServiceUnitTests {
  [Fact]
  public async Task GivenValidKeyEntryPairInDb_WhenFetchingEntryOfTheKey_ThenEntryIsReturned() {
    ...
  }
}


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

&lt;/div&gt;
&lt;h3&gt;
  
  
  Does it test more than one thing?
&lt;/h3&gt;

&lt;p&gt;A test that tests more than one thing at a time can be difficult to derive meaning from and becomes less useful with respect to pinpointing where a bug lives in the code.&lt;/p&gt;

&lt;p&gt;One thing does not mean one field or just one value, but rather the resulting state. A rule of thumb: primitive fields and such can be checked together as a way of validating the state of an object, but do make sure to add more informative messages when you have more than one assertion in a test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;With the &lt;a href="https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices#naming-your-tests" rel="noopener noreferrer"&gt;{method}_{condition}_{result}&lt;/a&gt; naming convention, this is given:
```c#
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;[Fact]&lt;br&gt;
public async Task ReadSectionAsync_ValidKeyOfExistingEntry_ReturnsEntry() {&lt;br&gt;
  var expected = dbKeyEntryPair.Entry;&lt;br&gt;
  ...&lt;br&gt;
  var actual = await service.ReadSectionAsync(validKey);&lt;br&gt;
  ...&lt;br&gt;
  Assert.Equal(expected, actual);&lt;br&gt;
}&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Is it well arranged?
A well-arranged test does not configure some state, execute some code, configure some more, execute some more, assert something and keep on mixing these things. In the abstract, a test that does one thing, and one thing only, validates that the code under testing from some configured state performs some execution, returns something expected and finds rest in some expected state.
- Microsoft advice adding the three A's as code comments:
```c#


[Fact]
public async Task {TestName}(){
  // Arrange
  {Configuration}
  // Act
  var actual = {subject}.{Method}({args});
  // Assert
  {Assertion(s)}
}


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

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;There is some disagreement out there in the Great Ether with regards to where one should put shared static configuration, such as the initialization of the test subject(s) and mocks as well as common configuration of the subject(s) and mocks. It is my opinion that initialization can occur in the constructor of the test class and that this will be the same for all tests in a test class. Configuring the subject(s) and mocks thus belongs to the configuration step of each test, as they likely vary.
```c#
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;public class CmsServiceUnitTests {&lt;br&gt;
  public Mock writeRepoMock;&lt;br&gt;
  public Mock readRepoMock;&lt;br&gt;
  public CmsService subject;&lt;/p&gt;

&lt;p&gt;public CmsServiceUnitTests() {&lt;br&gt;
    readRepoMock = new Mock();&lt;br&gt;
    writeRepoMock = new Mock();&lt;br&gt;
    subject = new CmsService(Mock.Of&amp;gt;(), readRepoMock.Object, writeRepoMock.Object)&lt;br&gt;
  }&lt;/p&gt;

&lt;p&gt;const string validKey = {key of valid format};&lt;br&gt;
  const string entry = {content of entry};&lt;/p&gt;

&lt;p&gt;[Fact]&lt;br&gt;
  public async Task ReadSectionAsync_ValidKeyOfEntry_ReturnsEntry() {&lt;br&gt;
    // Arrange&lt;br&gt;
    readRepoMock.Setup(m =&amp;gt; m.ReadAsync(validKey)).ReturnsAsync(entry);&lt;br&gt;
    var expected = entry;&lt;br&gt;
    // Act&lt;br&gt;
    var actual = subject.ReadSectionAsync(validKey);&lt;br&gt;
    // Assert&lt;br&gt;
    Assert.Equal(expected, actual);&lt;br&gt;
  }&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Does logic occur?
A great way to detect whether a test only does one thing or not is to check whether it contains logic, such as a `switch`-, an `if`- or a `for`-statement. These statements make the test a lot less readable seeing as the state of the subject and the input at the time of method calling becomes something computed, rather than something set (which can simply be read).
- I must admit that I sin with respect to this when compressing testcases - sometimes I find it easier to write a lot of testcases using one parameterized test, where some of the arguments inform the testcase to configure in a particular way, instead of splitting up the testcases into multiple separate parameterized tests. However, just because something is easy doesn't mean you should do it!

### Is it a typical test?
Here _typical_ refers to whether or not the test follows some sacred dogma allowing it to be categorized easily into some preconceived type, such as End-to-end integration tests, unit tests, or simply tests that fit in to the overall test strategy.

If the test does not neatly fit into a category, consider refactoring it in such a way that it does. A way to do this could potentially be to clone the test if it resides within a canyon of two or more categories, in order to ensure that each category gets its own version of the test.

### Does it follow Clean Code Principles?
In spite of popular belief, test code is actually also code and should in general receive the same care you provide to any other code. There's great benefits to this, such as readability, reusability and flexibility.
- To demonstrate this, consider a test class containing a large number of tests where the subject has some internal state that may vary. While one state can be considered both an initial and valid, all other states can abstractly be thought of as mutations of this first state. We can use this sort of thinking when coding our tests. In each test following `// arrange`, we use the method `Setup();`. Each test then deviates from this initial state by mutating it, perhaps with a `SetSubjectDependency(s =&amp;gt; s.{dep}, null)` in a test validating how the subject handles internal nullreferences.

### Is the test independent?
Tests which share state and space with other tests are at risk of experiencing bugs themselves because the timing of execution of the tests may affect their correctness. This should be avoided by instantiating dependent objects for each test.
- If you want to increase readability of a test by reducing bloat by moving some variables to the class scope or similar, or perhaps refactoring away some magic constants, make sure they are immutable in the outer scope. If this is not an option, consider not moving it to the outer scope. Otherwise, you are vulnerable to undesirable behavior in your tests.

### Is the test timely (relatively)?
A test that is never run is a bad test as it adds no value. A tests that motivates the developer not to run it, perhaps because it takes a lot of time to set up or it just runs slowly, **is a bad test**.
  - A test is a slow test, seen relatively to how often you'd like to run it. If a test suite is run once a month, because the code it touches is very static, or the suite is overly thorough relatively to everyday development, it is acceptable that it takes longer to run. Test suites that are expected to run on a daily basis, perhaps even hourly basis, should be quick, though! Otherwise, you will end up getting more coffee than is healthy for you, with all those coffee breaks.

### Is the test repeatable?
A test which has stochastic behavior, such as being real-time dependent, using pseudo-randomness generators or threading timing are inherently bad tests because a pass does not guarantee anything (a false positive), and a failure can be hard to reproduce.

Believe me! In my more inexperienced days, I once spent two days trying to reproduce a test failure which turned out to only occur when the clock on the machine had gone past 19:00.

These qualities makes the test unreliable. To fix this, you fix the uncertainties. Mock the problematic dependencies, in relation to which you might possibly need to introduce wrappers, in order to gain control over what they return. In that way, the test result becomes reliable, although the result is less general and more specific - but do not fool yourself! This was already the case, now we just know the specifics.

- This also implies that you should not use a PRG or the clock by yourself to setup or run your tests!
- Sometimes, it cannot be avoided to have uncertainty in your tests, for instance if you are integration testing in conjunction with some third party code. In that case, there are some strategies concerning how to avoid false positives, such as repeating the code x times, but you should be aware that there are not absolutes in the realm of probabilistic.

## What makes a test good?
Having uncovered what makes a test bad, the next logical step is to explore how to identify a good test. Rather than letting this blogpost go on forever, I'll let you ponder upon the matter until the release of the second half of this short series on testing, wherein I'll elaborate further on testing and how to spot good tests - so watch out for part 2! 

# Conclusion
To sum up this blogpost, however, we've now compiled a list of things to check for when you suspect a test of being bad and need to identity what needs to be changed.

In case you already forgot, here's a shorter version:
1. Know what you are testing.
2. Name the test accordingly.
3. Test one thing at a time.
4. Arrange your tests.
5. Make your test readable.
6. Make your test simple.
7. Make your test timely.
8. Make your test independent.
9. Make your test repeatable.

... and if the test is without purpose, get rid of it.

## Remark
If there is anything you wonder about, disagree with or would like added to this blog post - leave a comment!
## References
My personal experience,
https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-best-practices
https://martinfowler.com/bliki/GivenWhenThen.html
https://gist.github.com/wojteklu/73c6914cc446146b8b533c0988cf8d29 (Clean Code by Robert C. Martin summary)
https://docs.microsoft.com/en-us/aspnet/core/test/integration-tests?view=aspnetcore-6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

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