<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Optivem Journal: Test Driven Development]]></title><description><![CDATA[Legacy Code is a nightmare to maintain. You tried TDD, but it didn’t work. TDD in Legacy Code seems impossible. That’s why I made the TDD in Legacy Code series.]]></description><link>https://journal.optivem.com/s/test-driven-development</link><image><url>https://substackcdn.com/image/fetch/$s_!0CjJ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F9abead4c-3f54-46b1-96aa-7033849416df_200x200.png</url><title>Optivem Journal: Test Driven Development</title><link>https://journal.optivem.com/s/test-driven-development</link></image><generator>Substack</generator><lastBuildDate>Wed, 15 Apr 2026 21:23:10 GMT</lastBuildDate><atom:link href="https://journal.optivem.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Valentina Jemuović, Optivem]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[optivem@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[optivem@substack.com]]></itunes:email><itunes:name><![CDATA[Valentina Jemuović]]></itunes:name></itunes:owner><itunes:author><![CDATA[Valentina Jemuović]]></itunes:author><googleplay:owner><![CDATA[optivem@substack.com]]></googleplay:owner><googleplay:email><![CDATA[optivem@substack.com]]></googleplay:email><googleplay:author><![CDATA[Valentina Jemuović]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[TDD: If Your Test Never Fails, It’s Broken]]></title><description><![CDATA[The RED step]]></description><link>https://journal.optivem.com/p/tdd-if-your-test-never-fails-its-broken</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-if-your-test-never-fails-its-broken</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Tue, 07 Apr 2026 06:02:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/ec518127-dfa2-4e37-993b-d671b8e93624_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128075; <em>Hello, this is Valentina with the free edition of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Now you&#8217;ve written a test.</p><p>But does it fail?</p><p>If it doesn&#8217;t, you have no proof that your implementation makes a difference.</p><p>A test that always passes is worse than no test.</p><p>It gives you a false sense of security.<br>It hides bugs instead of exposing them.</p><p>That&#8217;s why the <strong>RED step matters</strong>.</p><p>You watch it fail.</p><p>That failure is evidence.</p><p>Later, when it turns GREEN, you know the code caused it &#8212; not luck, not a misconfigured test, not a false positive.</p><h2>&#9889;Can the Test Actually Fail?</h2><p>If you&#8217;ve seen it fail:</p><ul><li><p>It confirms the test is valid.</p></li><li><p>It means that the later GREEN step actually proves your code works.</p></li><li><p>It protects you from false positives &#8212; those sneaky tests that always pass, giving you a fake sense of correctness.</p></li></ul><p>TDD makes it unavoidable.</p><p>No RED? No trust in your code.</p><h2>Why Developers Skip It (And Regret It)</h2><p>It&#8217;s tempting to skip RED:</p><ul><li><p>&#8220;I know this code will work, so why watch it fail?&#8221;</p></li><li><p>&#8220;It&#8217;s faster to just implement and see GREEN.&#8221;</p></li></ul><p>But skipping RED is like installing a fire alarm that never goes off &#8212; you won&#8217;t know something&#8217;s broken until it&#8217;s too late.</p><p>Watching the test fail is the <strong>cheapest, fastest bug prevention you can get</strong>.</p><h2>RED Before GREEN</h2><p>TDD isn&#8217;t just about writing tests.</p><p>It&#8217;s about <strong>proof</strong>.</p><p>Proof that your test matters.<br>Proof that your code works.<br>Proof that the system behaves as expected.</p><p>You can take a step further with Acceptance Test&#8211;Driven Development (ATDD).</p><p>Instead of just asking:</p><blockquote><p>&#8220;Does my code work?&#8221;</p></blockquote><p>ATDD asks:</p><blockquote><p>&#8220;Does the system behave as the user expects?&#8221;</p></blockquote><p>It&#8217;s less about writing more tests and more about making sure everyone &#8212; Devs, QA, and Product Owners &#8212; agrees on what &#8220;done&#8221; really means.</p><p>The cool part? Fewer arguments about whether something is broken, fewer regression bugs, and a lot less late-night firefighting &#8212; because expectations are clear <strong>before you write a single line of code</strong>.</p><div><hr></div><p>&#128640; <strong>Join me for: <a href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop">ATDD &#8211; Acceptance Testing Workshop</a></strong></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop&quot;,&quot;text&quot;:&quot;Join the workshop &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop"><span>Join the workshop &#8594;</span></a></p><p>Limited spots. Get <strong>100 EUR off with code EARLYBIRD100</strong></p><p></p>]]></content:encoded></item><item><title><![CDATA[Clean Code Is NOT Optional]]></title><description><![CDATA[It&#8217;s tempting to write code fast...]]></description><link>https://journal.optivem.com/p/clean-code-is-not-optional</link><guid isPermaLink="false">https://journal.optivem.com/p/clean-code-is-not-optional</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Wed, 01 Apr 2026 06:02:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e5f34d3e-bd39-4e7d-ad18-2cd0c5357885_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128075; <em>Hello, this is Valentina with the free edition of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>It&#8217;s tempting to write code fast and plan to clean it up later.</p><p>Skip the naming.<br>Duplicate a bit of logic.<br>Add &#8220;just one more if&#8221;.</p><h2>Messy Code Is a Tax</h2><p>Every change on top of messy code costs more:</p><ul><li><p><strong>Features take longer</strong> because you can&#8217;t trust what&#8217;s already there. You read more than you write, trying to figure out what the code actually does.</p></li><li><p><strong>Bugs hide</strong> in unclear abstractions and duplicated logic. You fix something in one place and miss the copy-pasted version three files over.</p></li><li><p><strong>Refactoring is painful</strong> because dependencies are tangled. You pull one thread and everything unravels.</p></li></ul><p>So you slow down. Every change gets harder. Every decision gets riskier. Every task takes longer than it should.</p><p>And the worst part? You <em>know</em> you should fix it, but now you can&#8217;t justify the time &#8212; because there&#8217;s a backlog of features waiting.</p><p>This is how codebases rot. Not from one bad decision, but from hundreds of small ones that compound.</p><blockquote><p>No matter how slow you are writing clean code, you will always be slower if you make a mess. &#8212; Uncle Bob</p></blockquote><p>Clean code may feel slower at first. But every line you write on top of it is faster, safer, and less stressful.</p><p>The hard truth: Messy code always costs more time than taking the time to do it right.</p><h2>But How Do You Keep Code Clean &#8212; and Keep It Working?</h2><p>Say you&#8217;ve written clean, well-structured code. You refactor a service, rename some methods, extract a class. The code reads well. You&#8217;re confident it&#8217;s correct.</p><p>But is it?</p><p>How do you know that the order flow still works end to end? That the payment integration didn&#8217;t break? That a customer can still check out?</p><p>You don&#8217;t &#8212; unless you have tests that verify <em>behavior</em>, not implementation.</p><h2>Clean Code Needs a Safety Net</h2><p>Unit tests are fast. They give you quick feedback and make refactoring feel safe.</p><p>But even the best unit tests have a blind spot.</p><p>They verify pieces in isolation. They mock the database, stub the API, skip the serialization. So when everything passes, you know your <em>unit</em> <em>logic</em> works &#8212; but you don&#8217;t know if the <em>system logic</em> works.</p><p>The gaps live at the boundaries: the database query that returns data in a different shape than you assumed. The HTTP layer that silently drops a field. The integration that worked in isolation but breaks when it meets real I/O.</p><p>Unit tests can&#8217;t catch these problems &#8212; not because they&#8217;re poorly written, but because that&#8217;s not what they&#8217;re designed to do.</p><p>Acceptance tests fill that gap. They exercise the system end-to-end, through the same boundaries your users hit:</p><p>A <strong>unit test</strong> says: &#8220;This function calculates the discount correctly.&#8221;</p><p>An <strong>acceptance test</strong> says: &#8220;When a customer applies a coupon at checkout, the total price is reduced and the order goes through.&#8221;</p><p>They&#8217;re slower than unit tests. You won&#8217;t run them on every keystroke. But they answer the question that unit tests can&#8217;t:</p><p><strong>Does this actually work for the user?</strong></p><h2>Clean Code Without Acceptance Tests Is a Risk</h2><p>Clean code keeps you moving fast. Unit tests ensure your refactoring doesn&#8217;t break the unit's logic. So why do you need anything else?</p><p>Because unit tests verify your code works <em>in isolation</em>. Acceptance tests verify your system works <em>in reality</em>.</p><p>You can have clean code, a full suite of passing unit tests, and still deploy a broken checkout flow &#8212; because the bug lives at a boundary that no unit test touches.</p><ul><li><p><strong>Clean code</strong> lets you move fast.</p></li><li><p><strong>Unit tests</strong> make sure the pieces work.</p></li><li><p><strong>Acceptance tests</strong> make sure the system works.</p></li></ul><p>One without the other will eventually slow you down.</p><p>You need all three.</p><h2>Where do you start?</h2><p>If you&#8217;re working in a greenfield project, you can build all three from day one.</p><p>But what about legacy code &#8212; where there are no tests, and the code is too messy to unit test?</p><p>You don&#8217;t start with unit tests. You can&#8217;t &#8212; the code isn&#8217;t structured for them yet.</p><p>You start with acceptance tests.</p><p>They don&#8217;t need clean code. They don&#8217;t need dependency injection or isolated modules. They test the system from the outside, through the same entry points your users hit. That means you can add them to any codebase, no matter how messy.</p><p>Once acceptance tests are in place, you have a safety net. Now you can refactor toward clean code and add unit tests &#8212; without breaking what already works.</p><p>Ready to put this into practice?</p><p>I&#8217;m running a hands-on <strong><a href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop">Acceptance Testing Workshop</a></strong> on May 27&#8211;28 (4 hours).</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop&quot;,&quot;text&quot;:&quot;Join the workshop &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop"><span>Join the workshop &#8594;</span></a></p><p>Limited spots. Register now with the early bird discount - <strong>100 EUR off with code EARLYBIRD100</strong></p>]]></content:encoded></item><item><title><![CDATA[TDD & ATDD]]></title><description><![CDATA[In Microservice Architecture]]></description><link>https://journal.optivem.com/p/tdd-and-atdd-in-microservice-architecture</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-and-atdd-in-microservice-architecture</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 27 Mar 2026 07:02:39 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/5beed640-9a0c-4081-b7db-37b6bcb7f5d7_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>When I first got into TDD, I thought I had it figured out.</p><p>I was reading Kent Beck, Martin Fowler&#8230; all of it just made sense.</p><p>I was really into clean code and unit tests.</p><p>I knew about e2e testing, but I saw it as QA&#8217;s job, not mine. Those tests were really badly written and constantly breaking. And to be honest, I saw it as boring and something that developers shouldn&#8217;t be doing.</p><p>I saw the whole CI/CD pipeline as a separate thing done by a DevOps engineer &#8212; not me.</p><div><hr></div><p>Still, no matter how many unit tests were written, management kept on complaining:</p><blockquote><p>&#8220;Why are there still so many bugs?&#8221;</p><p>&#8220;Why is everything taking so long?&#8221;</p><p>&#8220;I thought the last release fixed this!&#8221;</p><p>&#8220;Customers are frustrated &#8212; something has to change!&#8221;</p></blockquote><div><hr></div><p><strong>&#9889;Want to skip the pain and go straight to the solution?</strong></p><p><strong>Every Release Is a Nightmare</strong> doesn&#8217;t have to be your reality.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop&quot;,&quot;text&quot;:&quot;Join the workshop &#8594;&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://optivem.thinkific.com/products/courses/2026-05-27-acceptance-testing-workshop"><span>Join the workshop &#8594;</span></a></p><p>Limited spots. Register now with the early bird discount - <strong>100 EUR off with code EARLYBIRD100</strong></p><div><hr></div><h2>A Story That Stuck With Me</h2><p>Later, I stumbled across something Dave Farley shared. The teams were practicing TDD&#8230; they were lots of unit tests, all green &#8212; but the system was failing in QA environment, for possibly weeks. QA engineers constantly had to play catch-up with their e2e tests.</p><p>And that&#8217;s what got Dave Farley to develop acceptance tests.</p><div><hr></div><p>I realized I had to see the bigger picture.</p><p>That meant looking at the whole continuous delivery pipeline and understanding how all the pieces fit together.</p><p>In the commit stage, we&#8217;re doing TDD and writing unit tests (and component tests)&#8212; making sure each component behaves the way we expect.</p><p>But further down the pipeline, there&#8217;s the acceptance stage, where ATDD comes in &#8212; checking that all those pieces actually work together as a system.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!u0K5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!u0K5!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 424w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 848w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!u0K5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png" width="900" height="1110" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1110,&quot;width&quot;:900,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:120470,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/191875686?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!u0K5!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 424w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 848w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 1272w, https://substackcdn.com/image/fetch/$s_!u0K5!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fea3036e5-1075-443d-a679-551a9bf49e30_900x1110.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>&#9889;TDD &amp; ATDD in Microservice Architecture</h1><h2>ATDD: Seeing the System as a Whole</h2><p>If you zoom out and look at the system&#8230; it starts with a user story.</p><p>And that story comes with <strong>acceptance criteria</strong> &#8212; the conditions that tell you: <em>did we actually deliver what the user needs?</em></p><p>Instead of just reading those criteria&#8230; we can turn each one into an <strong>acceptance test</strong>. It&#8217;s basically like 1:1 mapping.</p><p>And these tests are very different from unit tests.</p>
      <p>
          <a href="https://journal.optivem.com/p/tdd-and-atdd-in-microservice-architecture">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD: No Test? No Implementation.]]></title><description><![CDATA[Test the Requirement First]]></description><link>https://journal.optivem.com/p/tdd-no-test-no-implementation</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-no-test-no-implementation</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Mon, 23 Feb 2026 11:18:58 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fafbaf5b-cfb1-4fa2-a27a-cef3ba6a3000_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128075; <em>Hello, this is Valentina with the free edition of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Most devs start coding with only a hazy idea of what &#8220;done&#8221; really means.</p><ul><li><p>You assume requirements are clear.</p></li><li><p>You assume you understand the edge cases.</p></li><li><p>You assume QA will catch any gaps.</p></li></ul><p>TDD forces you to confront assumptions before you touch the code.</p><p><strong>It&#8217;s not about writing more tests.</strong><br><strong>It&#8217;s about clarity, assurance, and focus.</strong></p><p>When you know you can test a requirement, you know exactly what success looks like.</p><p>And that changes everything &#8212; from how you design your interface to how you structure your implementation to how fast you can deliver working software.</p><h2>&#9889;Can You Even Test the Requirement?</h2><p>Before you write code, TDD forces you to ask:</p><blockquote><p>Can I write a test for this requirement?</p></blockquote><p>If you can&#8217;t, something&#8217;s wrong.</p><p>Maybe:</p><ul><li><p>The requirement is vague.</p></li><li><p>There&#8217;s no concrete example.</p></li><li><p>Nobody knows what &#8220;done&#8221; really means.</p></li></ul><p>And here&#8217;s the uncomfortable truth:</p><p>If you can&#8217;t construct an example to verify the requirement&#8230;<br>&#8230; you&#8217;re about to implement something blind.</p><p>You might push code that looks correct.<br>It might even pass code reviews.<br>And yet&#8230; it may fail silently in production.</p><p>TDD flips the script.</p><p>The first checkpoint isn&#8217;t your implementation.<br>It&#8217;s the requirement itself.</p><p><strong>No test? No implementation.</strong></p><p>That simple rule prevents hours (or days) of wasted effort, wasted code, and wasted frustration.</p><h2>&#9889;TDD &amp; ATDD</h2><p>TDD is amazing at keeping <strong>your code correct</strong>, but it mostly protects <strong>your implementation</strong>.</p><p>ATDD (Acceptance Test&#8211;Driven Development) takes it one step further.</p><p>Instead of just asking:</p><blockquote><p>&#8220;Can I write a test that proves my code works?&#8221;</p></blockquote><p>ATDD asks:</p><blockquote><p>&#8220;Can I write a test that proves the system behaves as the user expects?&#8221;</p></blockquote><p>It shifts the focus from &#8220;my code works&#8221; to &#8220;the system works for everyone.&#8221;</p><ul><li><p>Requirements become executable specifications.</p></li><li><p>Developers, QA, and Product Owners are all aligned on what &#8220;done&#8221; really means.</p></li><li><p>Regression bugs drop, because everyone agrees on the expected behavior before a single line of code is written.</p></li></ul><p>Think of it this way:</p><ul><li><p>TDD protects the code.</p></li><li><p>ATDD protects the behavior.</p></li></ul><p>If you&#8217;re working on <strong>legacy systems</strong> or teams where QA keeps reporting regression bugs, ATDD can transform the process &#8212; turning vague requirements and tribal knowledge into tests that everyone trusts.</p><h2>&#9889;Release Without the Stress</h2><p>You know something is wrong with how testing is done.</p><p>This workshop is for engineers who refuse to accept that &#8220;this is just how it is.&#8221;</p><p><strong>Date &amp; Time:</strong> Wed Feb 25, 5-7PM (CET)<br><strong>Where:</strong> Live online<br><strong>Cost:</strong> &#8364;97 &#8212; (100% off for Optivem Journal paid members)</p><p><strong>&#128204;Spots are limited &#8211; Sign up here:</strong> <a href="https://optivem.thinkific.com/order?ct=4816abff-c281-4105-a6ab-0bceca765f6b">Acceptance Testing (Live Training)</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://optivem.thinkific.com/order?ct=4816abff-c281-4105-a6ab-0bceca765f6b&quot;,&quot;text&quot;:&quot;Reserve Your Spot&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://optivem.thinkific.com/order?ct=4816abff-c281-4105-a6ab-0bceca765f6b"><span>Reserve Your Spot</span></a></p><p>&#127873; <strong>Free for Paid Members </strong>- <a href="https://journal.optivem.com/p/discount">Claim your 100% discount</a><br>Not a member yet? <a href="https://journal.optivem.com/subscribe">Upgrade now</a> for immediate access and replays</p><p></p><p></p>]]></content:encoded></item><item><title><![CDATA[TDD: Test the API, NOT the world]]></title><description><![CDATA[Write fast and deterministic tests]]></description><link>https://journal.optivem.com/p/tdd-test-the-api-not-the-world</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-test-the-api-not-the-world</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 13 Feb 2026 09:23:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c00c418e-f1bf-43e9-b73d-a4cfc213166f_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me for <strong><a href="https://optivem.thinkific.com/products/live_events/2026-02-25-acceptance-testing-live-training">Acceptance Testing (Live Training)</a></strong> on Wed 25th Feb (17:00 - 19:00 CET) <em>(100% discount for Optivem Journal members)</em></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Many years ago, I used to think every test had to touch everything &#8212; the database, other services, payment providers&#8230; you name it. </p><p>Then I realized: <strong>that&#8217;s inefficient, feedback loop is too slow. </strong>We need tests at different levels.</p><p>A user adds a product to their cart, maybe ten times while browsing, and then finally hits checkout, then later cancels their order.</p><p>That&#8217;s two very different use cases: <strong>AddItemToCart </strong>and <strong>PlaceOrder</strong>. And each requires different tests.</p><h2>The problem: Use Cases and the External World</h2><p>Most real-world use cases depend on something external:</p><ul><li><p>Databases</p></li><li><p>Message brokers</p></li><li><p>External API services</p></li></ul><p>For example, the PlaceOrder use case involves the DB (we need to save orders), it involves message brokers (we publish an event, so that the reporting service can register the newly placed order), and it involves external API services (we need to use PayPal for processing payment for the placed order).</p><p>The problem with testing use cases in this way, involving the external world are the following:</p><ul><li><p>The test is too slow due to the I/O</p></li><li><p>We might not be able to test various logic scenarios</p></li><li><p>The test might not be able to run if the external system is not available</p></li></ul><h2>The solution: Isolation from the External World</h2><p>In order to be able to test our use case in isolation from the external world:</p><ul><li><p><strong>User-side api:</strong> We test the use case via its driving (incoming) port, so that we bypass UI / REST API</p></li><li><p><strong>Server-side api:</strong> We &#8220;mock out&#8221; the driven (outgoing) ports, so that we&#8217;re excluding DB, external APIs, etc. In this way, the use case depends on interfaces of the external world, and doesn&#8217;t know (or care) about concrete implementations</p></li></ul><p>This keeps your core logic <strong>isolated and maintainable</strong>.</p><h2>Server-side API: Enter Test Doubles</h2><p>When we write <strong>unit tests</strong>, those server-side ports are replaced with <strong>in-memory test doubles</strong>:</p><ul><li><p>Repositories Test Doubles (e.g. Order Repository Test Double)</p></li><li><p>Gateway Test Doubles (e.g. Notification Test Double, Payment Test Double)</p></li></ul><p>There are different types of Test Doubles: Dummies, Fakes, Stubs, Spies, Mocks (see Fowler&#8217;s <a href="https://martinfowler.com/bliki/TestDouble.html">Test Double</a> article)</p><p>The test doubles:</p><ul><li><p>Live entirely in memory</p></li><li><p>Run ultra fast</p></li><li><p>Behave predictably</p></li></ul><p>Basically, they let your tests focus on <strong>business logic</strong>, not &#8220;what the database or external API does today.&#8221;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OHx9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OHx9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 424w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 848w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 1272w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OHx9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png" width="1025" height="1264" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1264,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:154142,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/181080596?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!OHx9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 424w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 848w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 1272w, https://substackcdn.com/image/fetch/$s_!OHx9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F660821c1-9a0c-4705-99b3-bff58d075339_1025x1264.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><em>Note: The above image is for a microservice, but a similar image can be applied to the frontend. Also, in case of monolithic architecture, similar image can be applied to the monolith.</em></p><h2>AddItemToCart vs PlaceOrder (Real-life Example)</h2>
      <p>
          <a href="https://journal.optivem.com/p/tdd-test-the-api-not-the-world">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[SOLID vs TDD]]></title><description><![CDATA[Which One Actually Drives Design?]]></description><link>https://journal.optivem.com/p/solid-vs-tdd</link><guid isPermaLink="false">https://journal.optivem.com/p/solid-vs-tdd</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 29 Jan 2026 07:00:35 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d69fb555-fa43-4a67-80ae-d682b18f7f2f_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me for <strong><a href="https://optivem.thinkific.com/products/live_events/2026-02-25-acceptance-testing-live-training">Acceptance Testing (Live Training)</a></strong> on Wed 25th Feb (17:00 - 19:00 CET) <em>(100% discount for Optivem Journal members)</em></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>If you&#8217;ve ever sat in a Friday meeting, you&#8217;ve probably heard:</p><blockquote><p>&#8220;We need to follow SOLID!&#8221;<br>or<br>&#8220;TDD will guide our architecture!&#8221;</p></blockquote><p>But here&#8217;s the uncomfortable truth:</p><p><strong>Most developers treat SOLID like a rulebook and TDD like a silver bullet.</strong><br>And neither works that way.</p><p>The real question is: <strong>which one actually drives design?</strong></p><div><hr></div><h2>SOLID: The Smell Detector</h2><p>SOLID provides a set of principles for maintainable code. When you use SOLID principles to review code, you can notice design smells:</p><ul><li><p>Single Responsibility Principle: helps you notice volatile classes</p></li><li><p>Open/Closed Principle: helps you see where abstraction is needed</p></li><li><p>Liskov, ISP, DIP: point out awkward dependencies</p></li></ul><div><hr></div><h2>TDD: The Design Engine</h2><p>TDD (Test-Driven Development) helps us design in the following way:</p><ul><li><p>Red &#8594; write a failing test &#8594; this is forcing us to design the interface that exposes some behavior</p></li><li><p>Green &#8594; write the minimum code to pass &#8594; typically there is not much effort here regarding design, quick-and-dirty is fine</p></li><li><p>Refactor &#8594; we refactor code &#8212;&gt; clean design emerges</p></li></ul><p>Therefore, TDD leads to:</p><ul><li><p>Well-designed interfaces (in the RED step)</p></li><li><p>Well-designed implementation (in the GREEN step)</p></li></ul><h2>A Real-World Example: TDD First, SOLID After</h2>
      <p>
          <a href="https://journal.optivem.com/p/solid-vs-tdd">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD in Legacy Code - Maintainable Component Tests - Frontend]]></title><description><![CDATA[Many Frontend Teams write unmaintainable Frontend Component Tests - coupled to the UI. These tests are brittle. I'll show you how to refactor these tests to be maintainable, by using DSL & Drivers.]]></description><link>https://journal.optivem.com/p/maintainable-component-tests-in-legacy-code-frontend</link><guid isPermaLink="false">https://journal.optivem.com/p/maintainable-component-tests-in-legacy-code-frontend</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 08 Jan 2026 07:01:09 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/1a6832d4-becd-40c0-b321-7ccacc784c08_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me for <strong><a href="https://optivem.thinkific.com/products/live_events/2026-02-25-acceptance-testing-live-training">Acceptance Testing (Live Training)</a></strong> on Wed 25th Feb (17:00 - 19:00 CET) <em>(100% discount for Optivem Journal members)</em></p><div><hr></div><p><em>&#128274;Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply TDD in Legacy Code. This article is part of the <a href="https://journal.optivem.com/p/tdd-in-legacy-code-outline">TDD in Legacy Code</a> series. </em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Frontend Component Tests provide fast feedback</h2><p>We&#8217;ve seen in the previous article, <a href="https://journal.optivem.com/p/component-tests-in-legacy-code-frontend">Frontend Component Tests in Legacy Code</a>, that Frontend Component Tests can provide us with fast feedback. The Frontend Team can test Frontend in isolation, by stubbing out the Backend.</p><h2>But they can be a maintenance nightmare!</h2><p>In <a href="https://journal.optivem.com/p/component-tests-in-legacy-code-frontend">Frontend Component Tests in Legacy Code</a>, we illustrated the &#8220;simplest&#8220; Frontend Component Tests. But unfortunately, they are unmaintainable.</p><p>The simplest way to write a Frontend Component Test is to locate UI elements via Text, Role, ID, etc., then trigger some actions on those UI elements. For example: <em>(pseudocode)</em></p><pre><code><code>  const skuInput = screen.getByLabelText('SKU');
  fireEvent.change(skuInput, { target: { value: 'APPLE1001' } });</code></code></pre><p>The problem with these kinds of tests, is that if there is UX/UI Redesign, or some UI refactoring, that many such tests may break, so we have to waste time fixing tests.</p><h2>How to write maintainable Frontend Component Tests?</h2><p>In this article, I&#8217;ll show you how to introduce layers of abstraction, i.e. Component Test Architecture, so that you spend much less time writing &amp; maintaining these tests.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nYqK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nYqK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png" width="1456" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nYqK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here are the steps to introduce Maintainable Frontend Component Tests in Legacy Code. You&#8217;ll get tasks to implement in your GitHub Sandbox Project. &#11015;&#65039;&#11015;&#65039;&#11015;&#65039;</p>
      <p>
          <a href="https://journal.optivem.com/p/maintainable-component-tests-in-legacy-code-frontend">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD: Unit Tests - Backend (user-side API)]]></title><description><![CDATA[Unit tests define *what* are the outcomes of business logic, not *how* it is implemented.]]></description><link>https://journal.optivem.com/p/tdd-unit-tests-backend-user-side-api</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-unit-tests-backend-user-side-api</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 12 Dec 2025 07:01:42 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d7977189-e8ee-4e1c-8660-ebfdf6b6a832_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128073; Reserve Your Spot for the <strong><a href="https://atdd.optivem.com/">2026 ATDD Accelerator</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>When practicing TDD in Hexagonal Architecture, unit tests should target use cases - not internal classes, not frameworks, and not implementation details.</p><p>In other words: our tests interact with the business logic as an external observer.</p><h2>Unit Tests Target the User-Side API</h2><p>Unit tests talk only to the user-side API, which represents the component&#8217;s use cases:</p><ul><li><p><code>AddItemtoCart</code></p></li><li><p><code>RemoveItemFromCart</code></p></li><li><p><code>ViewCartContents</code></p></li><li><p><code>CalculateCartTotal</code></p></li><li><p><code>FilterCartItems</code></p></li><li><p><code>GetProductPrice</code></p></li></ul><p>The tests know nothing about:</p><ul><li><p><strong>Internal classes</strong><br>(e.g. <code>Cart</code>, <code>CartItem</code>, <code>PricingCalculator</code>, <code>InventoryChecker</code>)</p></li><li><p><strong>Frameworks</strong><br>(e.g. Spring, Hibernate, Express, NestJS)</p></li><li><p><strong>Persistence</strong><br>(e.g. SQL queries, ORM mappings, database schemas)</p></li><li><p><strong>Network calls</strong><br>(e.g. HTTP requests to inventory or payment services)</p></li><li><p><strong>Technical plumbing</strong><br>(e.g. transactions, caching, logging, retries)</p></li></ul><p>This is great because it means that we can do refactoring in a safe way.</p><p>As long as the use case behaves the same from the outside, we can:</p><ul><li><p><strong>Rename classes</strong><br>(e.g. <code>CartService</code> &#8594; <code>ShoppingCart</code>)</p></li><li><p><strong>Split logic</strong><br>(e.g. extracting pricing rules into a separate domain object)</p></li><li><p><strong>Merge logic</strong><br>(e.g. consolidating duplicate validation code)</p></li><li><p><strong>Move code around</strong><br>(e.g. shifting logic from a service into a domain entity)</p></li><li><p><strong>Change implementations entirely</strong><br>(e.g. in-memory storage &#8594; database, sync calls &#8594; async events)</p></li></ul><p>&#8230;and our tests remain green &#9989;</p><h2>Use Case First, Implementation Later</h2><p>In TDD, we write a unit test for a specific use case (the test describes behavior in business terms). Only then do we implement the use case (classes and code emerge naturally).</p><p>We focus purely on:</p><ul><li><p><strong>Inputs</strong><br>(e.g. <code>customerId</code>, <code>sku</code>, <code>quantity</code>, passed to <code>AddItemToCart()</code>)</p></li><li><p><strong>Outputs</strong><br>(e.g. cart contains the correct items and quantities, total price is calculated correctly)</p></li><li><p><strong>Observable side effects</strong><br>(e.g. an exception is thrown when adding an unavailable product, the cart is persisted via the repository interface)</p></li></ul><p>This:</p><ul><li><p><strong>Prevents premature design</strong><br>(e.g. you don&#8217;t design <code>CartItem</code> or <code>PricingCalculator</code> before knowing what behavior is required)</p></li><li><p><strong>Avoids over-engineering</strong><br>(e.g. you don&#8217;t implement caching, events, or complex inventory logic before it&#8217;s needed)</p></li><li><p><strong>Forces the design to stay aligned with real usage</strong><br>(e.g. the system only supports adding/removing items, calculating totals, and viewing the cart exactly as users would do, rather than unnecessary internal implementation details)</p></li></ul><h2>Big Picture</h2><p>The test enters through the same door as a client of the user-side API. </p><p>Since we want the test to span the hexagon only, we then have to &#8220;mock out&#8220; the server-side API, e.g. using fake adapters.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!GaWW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!GaWW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 424w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 848w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 1272w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!GaWW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png" width="1456" height="942" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:942,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:247271,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/180991061?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!GaWW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 424w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 848w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 1272w, https://substackcdn.com/image/fetch/$s_!GaWW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8fa60c-6da1-4dfe-b923-8b257d250773_2118x1370.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><h2>Real-Life Example: Ordering System</h2><p>For an e-commerce system, suppose we have a frontend and a backend. We model the backend using Hexagonal Architecture. Let&#8217;s see what the user-side API looks like on the backend:</p>
      <p>
          <a href="https://journal.optivem.com/p/tdd-unit-tests-backend-user-side-api">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD: High Coupling vs. Low Coupling Tests]]></title><description><![CDATA[When writing tests, it&#8217;s not enough to &#8220;just have tests.&#8221;]]></description><link>https://journal.optivem.com/p/tdd-high-coupling-vs-low-coupling-tests</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-high-coupling-vs-low-coupling-tests</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 14 Nov 2025 07:02:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/dc177dc7-951c-4b92-aa65-03a7067f49c2_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Join the <strong><a href="https://atdd.optivem.com/">ATDD Accelerator waitlist</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h3>&#128683; High coupling &#8211; Tests coupled to Structure &#10132; Fragile Tests</h3><p><strong>Do NOT write tests as specifications of your implementation.</strong></p><p>When your tests know too much about the system&#8217;s internals (specific classes, methods, or dependencies), the tests become tightly coupled to the implementation, i.e. the internal structure.</p><p>If you change an implementation class, the test will break. This kind of testing leads to fragile tests.</p><p>&#128269; Example symptoms:</p><ul><li><p>Tests instantiate internal classes directly</p></li><li><p>Tests depend on method names or call chains</p></li><li><p>Small refactorings cause test failures even when behavior hasn&#8217;t changed</p></li></ul><p>&#128165; The result:</p><ul><li><p>Refactoring becomes risky and slow</p></li><li><p>Developers fear touching the code</p></li><li><p>Tests no longer describe <em>behavior</em> &#8212; they describe <em>implementation details</em></p></li></ul><h3>&#9989; Low Coupling &#8211; Tests coupled to Behavior &#10132; Stable Tests</h3><p><strong>DO write tests as requirements of the system.</strong></p><p>Tests should communicate with the module&#8217;s public API and test the module&#8217;s external behavior. A module consists of a group of classes, where one class acts as the public class (exposes the module&#8217;s public API, it&#8217;s the entry point to the module) and the other classes are internal classes (they are implementation details of the module).</p><p>When our tests don&#8217;t know about implementation (treating it as a black box), we can change the internal implementation and we&#8217;re not going to break the tests.</p><p>We can do as much refactoring as we want, and the tests will not break.</p><p>&#9989; Characteristics:</p><ul><li><p>Tests verify the module&#8217;s behavior, not its internal implementation.</p></li><li><p>Internal classes can change freely without breaking tests.</p></li><li><p>You can refactor safely and move fast.</p></li></ul><p>&#128161; Example:</p><ul><li><p>Your tests call <code>OrderService.placeOrder()</code> instead of directly testing the underlying repository, entity, or validation class.</p></li><li><p>If you refactor <code>OrderService</code> or your validation class, the tests still pass &#8212; because behavior hasn&#8217;t changed.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m-hu!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m-hu!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 424w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 848w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 1272w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m-hu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png" width="1025" height="1167" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1167,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:121949,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/178781503?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m-hu!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 424w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 848w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 1272w, https://substackcdn.com/image/fetch/$s_!m-hu!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6dbe7e4c-c5c0-4f00-8a17-d0f747eb33e9_1025x1167.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Real-life Example: Ordering System</h2>
      <p>
          <a href="https://journal.optivem.com/p/tdd-high-coupling-vs-low-coupling-tests">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD in Legacy Code - Component Tests - Backend]]></title><description><![CDATA[How can Backend & Frontend teams get isolated feedback whether their part works, without waiting for the slow Acceptance Tests?]]></description><link>https://journal.optivem.com/p/component-tests-in-legacy-code-backend</link><guid isPermaLink="false">https://journal.optivem.com/p/component-tests-in-legacy-code-backend</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 23 Oct 2025 06:00:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/99bad525-4465-4fbe-b54e-0fa59d6e382f_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Join the <strong><a href="https://atdd.optivem.com/">ATDD Accelerator waitlist</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Testing the Frontend in isolation</h2><p>Previously, in <a href="https://journal.optivem.com/p/component-tests-in-legacy-code-frontend">Frontend Component Tests in Legacy Code</a>, we saw that the Frontend team can get feedback whether the Frontend works in isolation, by stubbing out the Backend. This means they don&#8217;t have to wait for the Backend team.</p><h2>Testing the Backend in isolation</h2><p>Similarly, the Backend team can get feedback whether the Backend works in isolation, by stubbing out External Systems. Backend Component Tests are independent of Frontend Component Tests, hence can be written in parallel.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SfIk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SfIk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SfIk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png" width="1456" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:230831,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/172556948?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SfIk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!SfIk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84876cb8-e92c-4130-b881-5ae3a40a6962_3886x1239.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here are the steps to introduce Backend Component Tests in Legacy Code. You&#8217;ll get tasks to implement in your GitHub Sandbox Project. &#11015;&#65039;&#11015;&#65039;&#11015;&#65039;</p>
      <p>
          <a href="https://journal.optivem.com/p/component-tests-in-legacy-code-backend">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD is NOT about high code coverage]]></title><description><![CDATA[Code Coverage shows you what you haven't tested, not how good your tests are]]></description><link>https://journal.optivem.com/p/tdd-is-not-about-high-code-coverage</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-is-not-about-high-code-coverage</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 17 Oct 2025 06:01:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/c9931c86-c936-4360-b767-de3a83eb05d8_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Join the <strong><a href="https://atdd.optivem.com/">ATDD Accelerator waitlist</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>You can achieve 100% code coverage having tests with zero assertions!<br><br>TDD isn&#8217;t about having useless or illogical tests just for the sake of reaching a certain metric.<br><br>The main goal of TDD is that we&#8217;re driven by specifications, and that the code we produce is testable and aligned with specifications.<br><br>High code coverage is just a byproduct of TDD, but not the goal.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!pTJt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!pTJt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 424w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 848w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 1272w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!pTJt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png" width="1025" height="574" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:574,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:136542,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/176143329?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!pTJt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 424w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 848w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 1272w, https://substackcdn.com/image/fetch/$s_!pTJt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F53e150ca-e593-44d1-beca-6172d694f8c3_1025x574.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>100% code coverage, 0 assertions</h2><p>You can literally hit every line of code with your tests &#8212; and still have no validation of behavior. This is called a &#8220;zero assertion test&#8220;.</p>
      <p>
          <a href="https://journal.optivem.com/p/tdd-is-not-about-high-code-coverage">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD: 1 unit test ≠ 1 class]]></title><description><![CDATA[TDD misconception: The class is the unit of isolation. That's wrong! Instead, the behavior is the unit of isolation.]]></description><link>https://journal.optivem.com/p/tdd-one-unit-test-does-not-equal-one-class</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-one-unit-test-does-not-equal-one-class</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 03 Oct 2025 07:03:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f8bff7d7-ea46-4bdf-b33e-062b61f10c95_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Join the <strong><a href="https://atdd.optivem.com/">ATDD Accelerator waitlist</a></strong></p><div><hr></div><p><em>&#128274; Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>I thought that: class = unit of isolation</h2><p>When I first started practicing TDD, I thought that &#8220;unit&#8221; in Unit Test meant &#8220;class.&#8221; I&#8217;d write a test class for every production class and a test method for every method. I&#8217;d isolate the class under test by mocking everything it touched - even things that didn&#8217;t make sense to mock: </p><ul><li><p>Write a test class for each production class</p></li><li><p>Write a test method for each production method</p></li><li><p>Isolate the class under test by mocking out all its dependencies</p></li></ul><p>Indeed, this is the same thing that Uncle Bob said many people try to do:</p><blockquote><p>&#8220;Most people who are new to TDD&#8230; create a kind of one-to-one correspondence between the production code and the test code. For example, they may create a <em>test class</em> for every production code class. They may create <em>test methods</em> for every production code method.&#8221;</p><p>Of course this makes sense, <em>at first</em>. After all, the goal of any test suite is to test the elements of the system. Why wouldn&#8217;t you create tests that had a one-to-one correspondence with those elements? Why wouldn&#8217;t you create a test class for each class, and a set of test methods for each method? Wouldn&#8217;t that be the <em>correct</em> solution?</p><p>And, indeed, most of the books, articles, and demonstrations of TDD show precisely that approach. They show tests that have a strong structural correlation to the system being tested. So, of course, developers trying to adopt TDD will follow that advice.</p><p>&#8211; Uncle Bob (<a href="https://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html">TDD Harms Architecture</a>)</p></blockquote><h2>&#9888;&#65039; But &#8220;class = unit of isolation&#8221; is problematic!</h2><p>Let&#8217;s see what happens when you write a Unit Test Class for each Production Class, and when you write a Unit Test Method for each Production Method.</p><p>Let&#8217;s say you refactor your code. Recall that refactoring means changing structure, without changing observable behaviors:</p><blockquote><p>&#8220;Refactoring (noun): a change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior&#8221;</p><p>&#8211; Martin Fowler (<a href="https://martinfowler.com/bliki/DefinitionOfRefactoring.html">Definition of Refactoring</a>)</p></blockquote><p>Examples of refactoring:</p><ul><li><p>Changing the signature of a public method</p></li><li><p>Moving a public method from one class to another</p></li><li><p>Splitting a class into multiple classes</p></li></ul><p>In these cases of refactoring, you&#8217;ll end up with broken unit tests! Why? Because the unit tests are coupled to the structure of the code! The tight coupling leads to fragile tests:</p><blockquote><p>&#8220;The problem is &#8211; and I want you to think carefully about this next statement &#8211; <em>a one-to-one correspondence implies extremely tight coupling</em>.</p><p>Think of it! If the structure of the tests follows the structure of the production code, then the tests are inextricably coupled to the production code&#8230;</p><p>It, frankly, took me many years to realize this. If you look at the structure of FitNesse, which we began writing in 2001, you will see a strong one-to-one correspondence between the test classes and the production code classes&#8230;</p><p>And, of course, we experienced some of the problems that you would expect with such a sinister design. We had fragile tests. We had structures made rigid by the tests. We felt the pain of TDD. And, after several years, we started to understand that the cause of that pain was that we were not designing our tests to be decoupled.</p><p>&#8211; Uncle Bob (<a href="https://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html">TDD Harms Architecture</a>)</p></blockquote><p>So what if the tests are fragile? Well, we end up with increased maintenance costs. Because when we are refactoring, the tests break, so we have double the effort:</p><ul><li><p>Effort of making the change in the code itself &#8212;&gt; this is necessary</p></li><li><p>Effort of &#8220;fixing&#8220; the broken test &#8212;&gt; this is a waste of time</p></li></ul><p>So then we don&#8217;t want to refactor! This leads to code rot. Unmaintainable code makes future code changes even more expensive!</p><p>To summarize, the belief that &#8220;class = unit of isolation&#8220; leads to higher maintenance costs and slower delivery.</p><h2>The alternative: &#8220;behavior = unit of isolation&#8220;</h2><p>In the above, we&#8217;ve seen the problem of structural coupling, where tests are coupled to the structure of code; for every class, there&#8217;s one test. This leads to fragile tests, causing higher maintenance costs (and slower delivery).</p><p>The alternative is behavioral coupling, where tests are coupled to behavior of the code; for every behavior, there&#8217;s one test. This leads to robust tests, causing reduced maintenance costs (and faster delivery).</p><p>This is exactly what Kent Beck remarked:</p><blockquote><p>&#8220;Tests should be coupled to the behavior of code and decoupled from the structure of code.&#8221;</p><p>&#8211; Kent Beck (<a href="https://x.com/KentBeck/status/1182714083230904320">Twitter</a>)</p></blockquote><p>Suppose that we have a class <code>BankAccount</code>, that exposes the <code>withdraw() </code>method. Internally, it calls classes <code>BalanceCalculator</code> and <code>FeeCalculator</code>. In that case, we could say that <code>BankAccount</code> is a &#8220;public&#8221; class, whereas <code>BalanceCalculator</code> and <code>FeeCalculator</code> are &#8220;internal&#8220; classes.</p><p>In cases of structural coupling, we write 1 Test Class for 1 Production Class:</p><ul><li><p><code>BankAccountTest</code> class for <code>BankAccount</code> class </p></li><li><p><code>BalanceCalculatorTest</code> class for <code>BalanceCalculator</code> class</p></li><li><p><code>FeeCalculatorTest</code> class for <code>FeeCalculator</code> class</p></li></ul><p>In case of behavioral coupling, we write a Test Class only for the &#8220;Public&#8220; Production Class (that exposed behavior) and we do NOT write any Test Classes for the &#8220;Internal&#8220; Production Classes (because they are just a structural implementation detail). So we just have:</p><ul><li><p><code>BankAccountTest</code> class for <code>BankAccount</code> class (because that&#8217;s the &#8220;public class&#8220;)</p></li></ul><p><em>Please note, in both cases, the code coverage will be the same.</em></p><p>In the case of behavioral coupling, if &#8220;internal&#8220; classes are refactored, it will not cause breakage to the tests, because tests are coupled only to the interface of the &#8220;public&#8220; class. So in this way, we reduce maintenance costs.</p><p>This means we are testing BankAccount, which traverses BalanceCalculator and FeeCalculator. We do NOT mock BalanceCalculator and FeeCalculator.</p><p><em>The only thing we&#8217;ll mock out are external dependencies that involve I/O (e.g. file system, database, network, etc.) or non-determinism (e.g. system clock).</em></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DF5z!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DF5z!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 424w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 848w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 1272w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DF5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png" width="582" height="683.069268292683" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1203,&quot;width&quot;:1025,&quot;resizeWidth&quot;:582,&quot;bytes&quot;:87579,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/174855269?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DF5z!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 424w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 848w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 1272w, https://substackcdn.com/image/fetch/$s_!DF5z!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9206dd1-0fad-4bea-970d-928d573add91_1025x1203.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h2>Real-life Example: Ordering System</h2>
      <p>
          <a href="https://journal.optivem.com/p/tdd-one-unit-test-does-not-equal-one-class">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[How to introduce ATDD in Legacy Code? (in 3 months)]]></title><description><![CDATA[You should stay with your Big Ball of Mud, and stay with your Messy Code. I'll explain why and what you can do instead.]]></description><link>https://journal.optivem.com/p/how-to-introduce-atdd-in-legacy-code-in-3-months</link><guid isPermaLink="false">https://journal.optivem.com/p/how-to-introduce-atdd-in-legacy-code-in-3-months</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Wed, 10 Sep 2025 06:18:44 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/665a5791-0b8a-4cad-85cf-49525519d605_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join 100+ engineers at my next FREE live event <strong><a href="https://maven.com/p/f39276/stop-breaking-production-atdd-in-legacy-code">Stop Breaking Production: ATDD in Legacy Code</a></strong> (Sep 24 at 5:00 PM CET)</p><div><hr></div><p><em>&#128274;Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply TDD in Legacy Code. This article is part of the <a href="https://journal.optivem.com/p/tdd-in-legacy-code-outline">TDD in Legacy Code</a> series.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>You&#8217;re stuck in maintaining a Legacy Product. There&#8217;s no tests, you&#8217;re relying on the slow Manual QA. Most of your team&#8217;s sprint time is spent in fixing regression bugs and reworking features. Business is angry why nothing is delivered.</p><p>Everyone accepts this as &#8220;it&#8217;s the way things are, there&#8217;s nothing we can do about it&#8220;.</p><h2>The &#8220;silver bullet&#8221; fallacies</h2><p>So your team got together, and they all acknowledge these problems:</p><ul><li><p>Delivery is too slow (and it keeps getting slower)</p></li><li><p>Too many regression bugs (and the bug count rises over time)</p></li></ul><p>But then, when it comes to how to solve the problem, this is where it starts getting really messy. Everyone has a different opinion of what&#8217;s the root cause, and what needs to be done first.</p><p>Some people see the problem with code and architecture:</p><blockquote><p>&#8220;AI is the solution to everything. If only we bought the next latest-and-greatest AI tool to write 90% of our code, then we&#8217;d be shipping fast.&#8220;</p><p>&#8220;We have an old tech stack. If only we moved to the next shiny programming language and the latest framework, then our problems would be solved.&#8220;</p><p>&#8220;The problem is that we have a monolith. If only we moved to microservices, then all our problems would be solved.&#8221;</p><p>&#8220;Our code is messy. We should focus on SonarQube reports. If only we had clean code, then all our problems would be solved.&#8220;</p></blockquote><p>Some people see that the problem is with our process of working:</p><blockquote><p>&#8220;The problem is our User Story tickets. If only the PO was writing more detailed tickets, then it would solve our problems. The PO is the root cause of all problems.&#8220;</p><p>&#8220;The problem is that we have too many Scrum meetings. If we eliminated those meetings, then developers would have more time to do real work.&#8221;</p><p>&#8220;The problem is JIRA, we have to spend too much time on the tickets. If only we moved to a simpler ticketing system, we&#8217;d have less wasted time.&#8220;</p><p>&#8220;The problem is we have a siloed organization and we&#8217;re not communicating well. If only we solved the people problem, then we&#8217;d have better delivery.&#8221;</p><p>&#8220;Our PR review process is not good enough. Let&#8217;s write a procedure on how to do it better. We also need to have multiple reviewers.&#8220;</p><p>&#8220;If only we had well-documented coding standards, then developers would do more quality work.&#8220;</p></blockquote><p>Some people see the problem as we&#8217;re understaffed:</p><blockquote><p>&#8220;We don&#8217;t have enough developers. If we hired more developers, then things would speed up.&#8220;</p><p>&#8220;We don&#8217;t have enough QA Engineers. If we hired more QA Engineers, then it would reduce testing time.&#8220;</p></blockquote><p>Some people see the problem as being that we don&#8217;t have tests:</p><blockquote><p>&#8220;Let&#8217;s automate E2E Tests. We could buy an AI tool to do that. Then we could get rid of Manual QA.&#8221;</p><p>&#8220;If we wrote Unit Tests and had 80% code coverage, then we wouldn&#8217;t have these bugs. It&#8217;s important to catch bugs early.&#8220;</p></blockquote><p>Some give up, and say the only solution is to start from scratch:</p><blockquote><p>&#8220;Everything is horrible. We should just fire everyone, hire 10X developers and rewrite everything from scratch.&#8220;</p></blockquote><h2>Do NOT start with Architecture Redesign.</h2><p>You try to redesign Architecture, for example, by making your Monolith modular. Or you try to switch from the Monolith to Microservices. Or you want to redesign your Microservices to escape the Distributed Monolith. Or you want to restructure your database to support a modular system. Because you heard &#8220;modular&#8220; means good.</p><p>&#10060; If you try Architecture Redesign, <strong>BUT</strong> you do <strong>NOT</strong> have Acceptance Tests (instead you&#8217;re relying on Manual QA), then you&#8217;re going to spend months fixing regression bugs caused by your &#8220;better&#8220; architecture <em>(and your architecture redesign branch redesign won&#8217;t ever be ready for production)</em>. You&#8217;ll end up with cleaner architecture, but it doesn&#8217;t work correctly, and isn&#8217;t deployed to production. This is negative ROI.</p><p><strong>&#9989; The right way: Stay with your Big Ball of Mud (for now).</strong></p><h2>Do NOT start with Clean Code &amp; Unit Tests.</h2><p>You&#8217;ve probably heard Uncle Bob promoting Clean Code &amp; Refactoring everywhere. SonarQube is reporting lots of code smells, so you have to fix them, right?</p><p>&#10060; If you try to refactor towards Clean Code, without Unit Tests, then you&#8217;ll cause regression bugs. So then it means you have to introduce Unit Tests first.  But since the existing codebase is a Big Ball of Mud (everything is tangled up, business logic is coupled to I/O), then it&#8217;s not Unit Testable, so then you have to break dependencies to introduce Unit Tests. As you break dependencies (for the purpose of ensuring Unit Testability), <strong>BUT</strong> you do <strong>NOT</strong> have Acceptance Tests, then you&#8217;ll introduce lots of Regression Bugs (and your &#8220;big refactoring&#8220; branches won&#8217;t ever be ready for production). You&#8217;ll end with cleaner code, that doesn&#8217;t work correctly, and isn&#8217;t deployed to production. This is negative ROI.</p><p><strong>&#9989; The right way: Stay with your Messy Code (for now).</strong></p><h2>So what should we do first? ATDD.</h2><p>It took me a decade to realize that the solution is to firstly introduce this:</p><ol><li><p>Pipeline</p></li><li><p>Acceptance Testing</p></li><li><p>ATDD</p></li></ol><p>When you have that foundation, then you&#8217;re ready for any other improvements. You&#8217;ll then be able to safely upgrade your Tech Stack, redesign your Architecture, introduce Unit Tests &amp; clean up your Code.</p><h2>How to introduce ATDD in 3 months?</h2><p>If you&#8217;re a Senior Software Engineer or Engineering Leader, who has a strong level of self-initiative, and you want to introduce ATDD in your Legacy Project with guidance rather than trial-and-error, then I can help you:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://atdd-accelerator.optivem.com/apply&quot;,&quot;text&quot;:&quot;Apply for the ATDD Accelerator Program&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://atdd-accelerator.optivem.com/apply"><span>Apply for the ATDD Accelerator Program</span></a></p><p>Now I&#8217;m going to share with you my step-by-step for implementing ATDD in Legacy Code in 3 months, without disrupting your feature delivery:</p>
      <p>
          <a href="https://journal.optivem.com/p/how-to-introduce-atdd-in-legacy-code-in-3-months">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD in Legacy Code - Component Tests - Frontend]]></title><description><![CDATA[ATDD provides business-facing feedback, but the feedback loop is too long. That's why we need CTDD, which requires us to write Component Tests.]]></description><link>https://journal.optivem.com/p/component-tests-in-legacy-code-frontend</link><guid isPermaLink="false">https://journal.optivem.com/p/component-tests-in-legacy-code-frontend</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Thu, 04 Sep 2025 06:01:29 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/9e77875e-b8f7-42c0-b586-9bfe2aac2c97_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me at the FREE live event <strong><a href="https://maven.com/p/f39276/stop-breaking-production-atdd-in-legacy-code">Stop Breaking Production: ATDD in Legacy Code</a></strong> (Sep 24 at 5:00 PM CET)</p><div><hr></div><p><em>&#128274;Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply TDD in Legacy Code. This article is part of the <a href="https://journal.optivem.com/p/tdd-in-legacy-code-outline">TDD in Legacy Code</a> series. </em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>ATDD provides business-facing feedback.</h2><p>Through our journey up to now in <em><a href="https://journal.optivem.com/p/tdd-in-legacy-code-outline">TDD in Legacy Code</a></em> series, we&#8217;ve introduced ATDD. We received major benefits from ATDD:</p><ul><li><p>We reached alignment between PO, Software Engineers &amp; QA Engineers, so that they have a shared understanding of requirements before Software Engineers start coding</p></li><li><p>Acceptance Tests provide us with an objective &#8220;Definition of Done&#8220; for User Stories &amp; Bug Tickets, and provide us with a real measure of progress</p></li><li><p>Software Engineers receive relatively fast feedback whether they satisfied Acceptance Criteria or whether they introduced Regression Bugs, they wait for the Pipeline&#8217;s Acceptance Stage (1hr) rather than waiting for Manual QA Engineers (days/weeks)</p></li><li><p>QA Engineers are able to bring much higher value to the team, (1) by contributing to team discussions to ensure good scenario coverage, as reflected in writing testable acceptance criteria, and (2) by being able to focus more on Exploratory Testing, Usability Testing (instead of repetitive Regression Testing)</p></li></ul><p>All the above, combined, means that we are able to deliver software safely &amp; quickly.</p><h2>But the ATDD feedback loop is too long.</h2><p>ATDD is excellent in providing us with business-facing feedback (did we satisfy requirements, or did we introduce regression bugs). However, we face the following issues due to the slow feedback loop:</p><ol><li><p>It takes a long time to get feedback for a new Acceptance Test. It may take several hours/days for all teams to finish their work, associated with making some Acceptance Test pass, e.g., the Frontend Team needed to make changes, and the Backend Team needed to make their changes. We have to wait for everyone to finish, and then we&#8217;re able to see the results of the Acceptance Test. This is a slow feedback loop (we had to wait hours/days).</p></li><li><p>If the Acceptance Test fails, we have no idea which team is at fault - is the problem with Frontend, or with the Backend? Or perhaps is there a problem of miscommunication between them, that their API expectations aren&#8217;t matching? So we have to do time-consuming troubleshooting, involving multiple teams.</p></li><li><p>When we fix regression bugs (because some Acceptance Tests failed), we have to wait for 1hr for the Acceptance Stage to finish, so that we can be sure that our fix is correct and that we didn&#8217;t break anything. <em>Similarly, when we do some refactoring, we have to we have to wait for 1hr for the Acceptance Stage to finish, so that we can be sure that our refactoring hasn&#8217;t broken anything.</em> Suppose some Acceptance Test(s) fail. We don&#8217;t know whether our commit caused the failure or some other interim commit from another team member caused the failure, so we may need to manually review/debug multiple commits to discover which commit(s) caused Acceptance Tests to fail.</p></li></ol><h2>That&#8217;s why we need CTDD.</h2><p>How to overcome the problems of ATDD?</p><p>We need an additional inner loop - Component Test Driven Development (CTDD). This means that each team internally would be able to specify (RED), implement &amp; verify (GREEN), and refactor (REFACTOR) their component, independently of other components. The benefits are:</p><ol><li><p>Our team doesn&#8217;t have to wait several hours/days for all other teams to complete their work for an Acceptance Test, but rather we get feedback in minutes whether our Component Test(s) associated with that Acceptance Test are passing, so we have assurance that our work is completed.</p></li><li><p>Our team doesn&#8217;t have to wait for a failing Acceptance Test to discover that we&#8217;ve introduced a bug. Instead, we&#8217;d most likely discover it through the Component Test. We can do troubleshooting within their team, no need to involve other teams.</p></li><li><p>When we fix a regression bug caused by our Component, or when we do refactoring, we can get fast feedback (minutes) whether or not the Component works correctly.</p></li></ol><h2>We need Component Tests to practice CTDD.</h2><p>A key skill in practicing CTDD is the ability to write Component Tests. That is why we first need to write some Component Tests last to gain practice, before we move on to CTDD.</p><p>In this article, we&#8217;ll show how to write Component Tests. Firstly, we&#8217;ll show Frontend Component Tests, and later we&#8217;ll also show Backend Component Tests.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nYqK!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nYqK!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png" width="1456" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:230831,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/149954757?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nYqK!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!nYqK!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a90eb85-5087-4289-8c9d-ddc919f47ec6_3886x1239.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Here are the steps to introduce Frontend Component Tests in Legacy Code. You&#8217;ll get tasks to implement in your GitHub Sandbox Project. &#11015;&#65039;&#11015;&#65039;&#11015;&#65039;</p>
      <p>
          <a href="https://journal.optivem.com/p/component-tests-in-legacy-code-frontend">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD in Legacy Code - Component Testable Architecture]]></title><description><![CDATA[Legacy Code might be tangled up so that it might not be Component Testable, which prevents us from introducing Component Tests & Contract Tests. We need Component Testable Architecture.]]></description><link>https://journal.optivem.com/p/component-testable-architecture-in-legacy-code</link><guid isPermaLink="false">https://journal.optivem.com/p/component-testable-architecture-in-legacy-code</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 29 Aug 2025 07:15:19 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d0abc5f1-0cae-472e-9bb3-7c9b97f38279_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join 100+ engineers at my next FREE live event <strong><a href="https://maven.com/p/f39276/stop-breaking-production-atdd-in-legacy-code">Stop Breaking Production: ATDD in Legacy Code</a></strong> (Sep 24 at 5:00 PM CET)</p><div><hr></div><p><em>&#128274;Hello, this is Valentina with a premium issue of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply TDD in Legacy Code. This article is part of the <a href="https://journal.optivem.com/p/tdd-in-legacy-code-outline">TDD in Legacy Code</a> series.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Legacy Code might not be Component Testable</h2><p>In <a href="https://journal.optivem.com/p/acceptance-testable-architecture-in-legacy-code">Acceptance Testable Architecture in Legacy Code</a>, we covered the problem where a System is not Acceptance Testable, whereby it&#8217;s statically coupled to External Systems, which included the following cases:</p><ul><li><p>Hard-coded connections to External HTTP APIs</p></li><li><p>Static calls to the System Clock and other non-deterministic sources</p></li><li><p>Static calls to complex external libraries</p></li></ul><p>Aside from the problem of static coupling between our System and External Systems, Legacy Code also often has the problem of static coupling within our System, between the Components themselves:</p><ul><li><p>Hard-coded connections from Frontend to Backend</p></li><li><p>Hard-coded connections between Microservices</p></li></ul><h2>We can&#8217;t introduce Component Tests</h2><p>To write Component Tests, we need to have Component Dependency Stubs. For example: (1) to write Component Tests for the Frontend, we need to be able to stub out the Backend, (2) to write Component Tests for Microservice #1, and assuming Microservice #1 depends on Microservice #2 and Microservice #3, we then need to stub out those dependent microservices.</p><p>We need Component Dependency Stubs because they enable us to test our Component in isolation.</p><p>At runtime, to switch between Real Component Dependencies and Component Dependency Stubs, we need Component Dependency Configurability.</p><h2>So we need to ensure Component Testable Architecture</h2><p>That&#8217;s why we need to make some changes to our source code to ensure Component Dependency Configurability.</p><p>But how do these changes&#8230; without risking the whole system?</p><p>Here are the steps for achieving Component Testable Architecture in Legacy Code. You&#8217;ll get tasks to implement in your GitHub Sandbox Project. &#11015;&#65039;&#11015;&#65039;&#11015;&#65039;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ZkAi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ZkAi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ZkAi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png" width="1456" height="464" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:227636,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/170257076?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!ZkAi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 424w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 848w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 1272w, https://substackcdn.com/image/fetch/$s_!ZkAi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e5e0e31-49b6-464e-9239-b5a055372903_3886x1239.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="https://journal.optivem.com/p/component-testable-architecture-in-legacy-code">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[TDD - Microservice Testing]]></title><description><![CDATA[Many developers are writing integration tests the wrong way - they write Broad Integration Tests, which have similar limitations as E2E Tests - limited scenarios, brittle & fragile.]]></description><link>https://journal.optivem.com/p/tdd-microservice-testing</link><guid isPermaLink="false">https://journal.optivem.com/p/tdd-microservice-testing</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Mon, 25 Aug 2025 06:01:07 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/3a5c6bca-f422-49fa-8c1b-96cfffee2217_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128640; Do you want stop regression bugs escaping to production? Join me - next FREE live event: &#8220;<a href="https://maven.com/p/f39276/stop-breaking-production-atdd-in-legacy-code">Stop Breaking Production: ATDD in Legacy Code</a>&#8221; (Sep 24 at 5:00 PM CET).</p><div><hr></div><p>&#128075; <em>Hello, this is Valentina with the free edition of the Optivem Journal. I help Engineering Leaders &amp; Senior Software Developers apply <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">TDD in Legacy Code</a>.</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Don&#8217;t write broad integration tests to compensate for everything that unit tests can't do.</p><p>Broad integration tests are slow &amp; fragile. They have similar limitations as E2E Tests, because both traverse across dependencies.</p><p>Unfortunately, I&#8217;ve seen many teams write broad integration tests!</p><p>Instead of writing broad integration tests, you need tests at different levels:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xK5B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xK5B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 424w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 848w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xK5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png" width="1025" height="1274" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1274,&quot;width&quot;:1025,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:116195,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/170802698?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xK5B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 424w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 848w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 1272w, https://substackcdn.com/image/fetch/$s_!xK5B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8c154705-1bb9-4171-a203-61e8cd2843fe_1025x1274.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><h3>Narrow Integration Tests</h3><p>Narrow Integration Tests are used to verify infrastructure logic (Driven Adapters). For example, the Order Microservice may have these Narrow Integration Tests:</p><ul><li><p>Narrow Integration Test for the Order Repository - to verify database integration (e.g. using ORM, SQL, NoSQL, etc.), e.g. when we add entities, can we retrieve them <em>(note that the test connects to a real database via Testcontainers)</em></p></li><li><p>Narrow Integration Test for the Event Published - to verify messaging queue integration (e.g. RabbitMQ, Kafka), that we are correctly mapping our events to the data structures required by the messaging brokers <em>(note that the test connects to a real messaging queue via Testcontainers)</em></p></li><li><p>Narrow Integration Test for the Product Gateway - to verify integration with another microservice, e.g. with the Product Microservice - that we are correctly mapping our domain to the requests needed by Product Microservice, and whether we&#8217;re correctly interpreting the responses from the Product Microservice <em>(note that the test connects to a stubbed version of the Product Microservice, not the real thing)</em></p></li><li><p>Narrow Integration Test for the Payment Gateway - to verify integration with an External System, e.g. PayPal - that we are correctly mapping our domain to the requests needed by PayPal, and whether we&#8217;re correctly interpreting the responses from the PayPal <em>(note that the test connects to a stubbed version of the PayPal, not the real thing)</em></p></li></ul><p>Narrow Integration Tests are also used to verify Presentation Logic (Driving Adapters). For example, suppose that Order Microservice exposes a REST API - then, we verify that we can correctly translate HTTP requests into Driving Port Requests, and that we can correctly map Driving Port Responses into HTTP Responses.</p><h3>Component Tests</h3><p>Component Tests are used to test each component in isolation from other Components.</p><p>For example, suppose that the Order Microservice depends on Product Microservice and depends on PayPal. In that case, we want to test a flow through the Order Microservice, starting at the Order Microservice REST API, including the real database (via Testcontainers) but excluding Component Dependencies (we stub out the Product Microservice) and excluding External System Dependencies (PayPal). In this way, the Order Microservice team can get feedback on whether Order Microservice itself works correctly.</p><h3>Contract Tests</h3><p>In the case of integrating with dependencies, since we use stubs, we want to be sure that the stubs match the real thing.</p><p>In the case of testing Order Microservice, we stub out the Product Microservice and we stub out PayPal. How do we know whether the stubs are actually valid, that their API matches the API of the real things? We use Contract Tests:</p><ul><li><p>Contract Tests for the Product Microservice &amp; Product Microservice Stub provide assurance that the Product Microservice Stub exposes the same API that the Order Microservice relies on when communicating with the real Product Microservice Test Instance</p></li><li><p>Contract Tests for PayPal &amp; PayPal Stub provide assurance that the PayPal Stub exposes the same API that the Order Microservice relies on when communicating with the real PayPal Test Instance</p></li></ul><p>Ultimately, we get assurance that the Real Dependency API and the Dependency Stub API match.</p><h3>Acceptance Tests</h3><p>Acceptance Tests provide us with assurance that business requirements are satisfied. They answer the question: Does the system work correctly (in isolation from external systems)?</p><p>For example, for an eShop System, we can test whether placing order works correctly, e.g. is the correct order price calculated. We do this by stubbing out ERP (an External System) to specify product pricing, so that we can verify, for some SKU &amp; quantity, whether our eShop calculates the correct order total.</p><h3>Summary</h3><p>Testing at these levels helps you catch issues faster, keep tests maintainable, and have assurance you&#8217;re building the product right.</p><p>To learn more, read the <a href="https://journal.optivem.com/p/modern-test-pyramid-visual">Modern Test Pyramid</a>.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/p/tdd-microservice-testing/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/p/tdd-microservice-testing/comments"><span>Leave a comment</span></a></p><div><hr></div><h4>Want to apply TDD in practice?</h4><p>You tried TDD, but it didn&#8217;t work. That's why I'm going to help you practice TDD step-by-step. Apply TDD on a sandbox project. <a href="https://journal.optivem.com/p/tdd-in-legacy-code-transformation">Access TDD in Legacy Code.</a></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">TDD &#183; Hexagonal Architecture &#183; Clean Architecture. Join 5K+ subscribers</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Modern TDD - Unit Level]]></title><description><![CDATA[When a Component has high Business Logic complexity, there will be many Component Tests, so the test execution time gets slower and slower due to multiplication of I/O calls. What to do?]]></description><link>https://journal.optivem.com/p/modern-tdd-unit-level</link><guid isPermaLink="false">https://journal.optivem.com/p/modern-tdd-unit-level</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 18 Jul 2025 06:02:06 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/8fb2cb22-5713-4ee7-904d-ba142f015280_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#128197; Join me for the live workshop <strong><a href="https://lu.ma/vg945412">ATDD in Legacy Code Roadmap</a></strong> on Wed 6th Aug (17:00 - 19:00 CEST) <em>(100% discount for Optivem Journal members)</em></p><div><hr></div><p><em>&#128274; Welcome to the premium Optivem Journal. I&#8217;ll help you apply TDD to escape the nightmare of Legacy Code. Join our paid community of 160+ senior engineers &amp; leaders for support on your TDD journey, plus instant access to group chat and live Q&amp;As:</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Previously, we covered the <a href="https://journal.optivem.com/p/modern-test-pyramid-unit-level">Modern Test Pyramid - Unit Level</a>, where we showed why we need Unit Level Tests (Unit Tests &amp; Narrow Integration Tests):</p><ul><li><p><strong>Unit Tests</strong> - Provide us with extremely fast feedback on correctness of business logic, by testing business logic in isolation from I/O concerns (hence, by isolating business logic from I/O, we get feedback and order of magnitude faster). As business logic complexity increases, the number of scenarios that need to be covered also increases, which is where the benefits of Unit Tests become even more visible.</p></li><li><p><strong>Narrow Integration Tests</strong> - Provide us faster feedback compared to Component Tests because we eliminate the combinatorial explosion in testing I/O logic.</p></li></ul><p>The question is, does it matter whether we write Unit Tests last (i.e. after code)&#8230; or write Unit Tests first (i.e. before code)?</p><div><hr></div><h2>Approach 0. Not writing Unit Level Tests</h2><p>A team might be practicing <a href="https://journal.optivem.com/p/modern-tdd-component-level">Component Level TDD</a>, without any Unit Tests.</p><p>We don&#8217;t have to write Unit Tests, or we might not even be able to write Unit Tests. We could be just writing Component Level Tests.</p><p><strong>Case 1: Cannot write Unit Tests:</strong> Suppose that our Component architecture is not unit-testable, because there&#8217;s no separation between business logic and I/O logic. Examples are:</p><ul><li><p>We have fat REST controllers that contain everything - executing business logic, communicating with databases and external systems, and sending back a response based on some logic</p></li><li><p>We have fat &#8220;service&#8220; classes that do both business logic and communicate with databases and external systems</p></li></ul><p>Since business logic is not isolated (it&#8217;s instead mixed with I/O concerns), it's not possible to test the business logic independently of I/O - unit tests are not feasible.</p><p><strong>Case 2: Choose not to write Unit Tests:</strong> The Component architecture might be unit-testable (i.e. business concerns are separate from I/O concerns), but we consciously choose not to write Unit Tests. E.g. where the Component is too simple and/or where the amount of business logic complexity (roughly approximated by LOC) is not significantly higher than the amount of I/O logic complexity, or where there is much more I/O complexity. Then, we might not see the ROI of Unit Testing.</p><h4>Problems solved with Component Level Tests</h4><ul><li><p>Component Level Tests help teams work effectively independently &amp; in parallel, because each team gets feedback on their Component in isolation</p></li></ul><h4>Problems not solved with Component Level Tests</h4><ul><li><p>Developer has to wait for several minutes to get feedback (due to I/O slowness) whether they introduced a regression bug - this is especially a problem for Components with high degree of business logic complexity</p></li></ul><p>The fundamental unsolved problem is that, due to the inclusion of I/O within all tests, it means the feedback loop is slow. The wait time of several minutes is too long to get feedback on business logic changes, causing developers context-switches, or preventing them from working incrementally (they may decide to batch up several changes prior to running the slow Component Tests, but then this increases the cost of debugging when some Component Test fails).</p><h2>Approach 1. Writing Unit Level Tests last</h2><p>At some point, in Components with high business logic complexity, the team recognizes that the waiting time for Component Tests is too slow because the Component Test suite grew a lot. Why? High business logic complexity &#8594; many scenarios &#8594; many (slow) Component Tests &#8594; feedback loop gets slower and slower.</p><p>So, the team realizes they want to adopt Unit Tests. Why? Because every Unit Test is an order of magnitude faster than a Component Test (Unit Test runs purely in-memory, Component Test includes I/O, in-memory is an order-of-magnitude faster than I/O). So we can then have hundreds/thousands of Unit Tests, and get feedback within seconds.</p><p>The team naturally starts by writing Unit Tests last. Even though they&#8217;re practicing TDD at the System Level, and at the Component Level, there is nothing to force them to practice TDD at the Unit Level. Their process might be:</p><ol><li><p>Write a failing Acceptance Test</p></li><li><p>For each team, working in parallel:</p><ol><li><p>Writes a failing Component Test</p></li><li><p>Writes some code</p></li><li><p>Writes Unit Tests &amp; Narrow Integration Tests (they pass)</p></li><li><p>Verify that all the Component Tests &amp; Contract Tests pass</p></li></ol></li><li><p>Verify that all the Acceptance Tests pass</p></li></ol><h4>Problems solved with Unit Level Tests last</h4><ul><li><p>The benefit is that each team gets fast feedback on whether their Business Logic works correctly, and relatively fast feedback on whether their Presentation/Infrastructure Logic works correctly</p></li></ul><h4>Problems not solved with Unit Level Tests last</h4><ul><li><p>The Unit Tests (and Narrow Integration Tests) might not be valid, they might not be testing what we expect to be testing. This is because we&#8217;ve never seen them fail. When we see passing Unit Tests (and Narrow Integration Tests) it doesn&#8217;t mean anything - they might be always-green tests, which are useless. So, they won&#8217;t be good at detecting bugs, which means we&#8217;ll end up with a higher percentage of failing Component Level Tests, thereby wasting more time debugging.</p><ul><li><p>We could partially try to handle this problem by using Code Coverage, to help us discover lines of code that are never executed by Unit Tests &amp; Narrow Integration Tests. This is useful in helping us add some missing tests.</p></li><li><p>However, Code Coverage can&#8217;t help us know whether we&#8217;re verifying behavior - lines of code could be executed, but its output might not be asserted at all (or only partially asserted). This is where we&#8217;d need Mutation Coverage, however, the problem is that Mutation Testing is too slow, it is impractical to run it with every commit, it might be run as a nightly job (or some other interval) but that results in slow feedback. Then, we would have to spend additional time updating our Unit Tests &amp; Narrow Integration Tests.</p></li></ul></li></ul><p>We end up with time wasted in late debugging &amp; late rework (because these Unit Tests &amp; Narrow Integration Tests are not good at detecting regression bugs, so failures are detected more at the Component Test Level). This makes development more expensive.</p><p></p>
      <p>
          <a href="https://journal.optivem.com/p/modern-tdd-unit-level">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Modern TDD - Component Level]]></title><description><![CDATA[When a System Level Test fails, we have no idea where's the problem: is the problem with the Frontend or with the Backend (which Microservice)? How can we avoid wasting time with inter-team debugging?]]></description><link>https://journal.optivem.com/p/modern-tdd-component-level</link><guid isPermaLink="false">https://journal.optivem.com/p/modern-tdd-component-level</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 04 Jul 2025 06:00:52 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/b3fdd5c2-eed3-4a08-8f05-e3437727ebd1_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Welcome to the premium Optivem Journal. I&#8217;ll help you apply TDD to escape the nightmare of Legacy Code. Join our paid community of 160+ senior engineers &amp; leaders for support on your TDD journey, plus instant access to group chat and live Q&amp;As:</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>Previously, in <a href="https://journal.optivem.com/p/modern-test-pyramid-component-level">Modern Test Pyramid - Component Level</a>, we showed why we need Component Level Tests (Component Tests &amp; Contract Tests):</p><ul><li><p><strong>Component Tests</strong> - Each team has assurance that their Component works correctly in isolation (i.e. that the Frontend works correctly in isolation, that the Backend/Microservices work correctly in isolation)</p></li><li><p><strong>Contract Tests</strong> - Each team has assurance that their Component can communicate with other Components &amp; External Systems (e.g., assurance that Frontend can communicate with Backend, that Microservice 1 can communicate with Microservice 2, etc.)</p></li></ul><p>The question is, does it matter if we write Component Tests last (i.e. after code)&#8230; or if write Component Tests first (i.e. before code)&#8230;</p><div><hr></div><p>&#128226; On <strong>Wed 9th July 17:00 CET</strong>, I&#8217;m hosting <strong>TDD &amp; Unit Tests - Part 4 (Live Q&amp;A)</strong>:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lu.ma/0l194lm9&quot;,&quot;text&quot;:&quot;Register now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://lu.ma/0l194lm9"><span>Register now</span></a></p><p><em>P.S. If you&#8217;re a Paid Member, you&#8217;ll receive a 100% discount (see Event Description for instructions on how to redeem your 100% discount).</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Approach 0. Not writing Component Level Tests</h2><p>A team might be practicing <a href="https://journal.optivem.com/p/modern-tdd-system-level">TDD - System Level</a> (ATDD), which aligns the whole team regarding business requirements and provides automated feedback whether they satisfied business requirements, whilst also eliminating Manual QA Regression Testing.</p><p>This team might NOT be writing Component Level Tests.</p><h4>Problems solved with System Level Tests</h4><ul><li><p>System Level Tests help teams align on requirements and get automated feedback on whether they satisfied the requirements. </p></li></ul><h4>Problems not solved with System Level Tests</h4><ul><li><p>Teams cannot test their components in isolation - i.e. the Frontend Team can&#8217;t test the Frontend in isolation, the Backend Team(s) can&#8217;t test the Backend/Microservices in isolation, but must wait for everyone to finish their job to get feedback. The late discovery of bugs in components leads to more expensive rework.</p></li><li><p>Teams have to wait for everyone to be done in order to know if they can integrate, i.e. are there any integration issues (e.g., mismatching contracts)? The late discovery of integration issues leads to more expensive rework across teams.</p></li></ul><p>Thus, the fundamental unsolved problem is that, due to the slow feedback loop, teams need to do late, expensive rework. This increases the total development cost, and reduces their capacity to deliver new features, i.e. thus limiting the business value that can be delivered.</p><h2>Approach 1. Writing Component Level Tests last</h2><p>At some point, the teams see that System Level Tests aren&#8217;t enough, that they need Component Tests.</p><p>When teams first start writing Component Levels Tests, they naturally tend to write them last (because they were accustomed to Test Last approaches). Thus, even though they might be writing Acceptance Tests first (practicing ATDD), they might still be writing Component Tests last. Their process might be the following:</p><ol><li><p>Write a failing Acceptance Test</p></li><li><p>Then each team works in parallel</p><ol><li><p>Frontend team writes some code, then when they finish coding, they write some Component Tests &amp; Contract Tests</p></li><li><p>Backend team(s) write some code, then when they finish coding, they write some Component Tests &amp; Contract Tests</p></li></ol></li><li><p>Verify that all the Acceptance Tests pass</p></li></ol><p><strong>Problems solved with Component Level Tests last</strong></p><ul><li><p>The benefit is that each team gets feedback on whether their Component works correctly in isolation (via Component Tests) and whether their Component can integrate well with other Components &amp; External Systems (via Contract Tests)</p></li></ul><p><strong>Problems not solved with Component Level Tests last</strong></p><ul><li><p>The teams may face integration issues due to misunderstandings. E.g. when the teams had a meeting and agreed on their contract, they had a misunderstanding, or perhaps they both had a good understanding but made spelling errors when implementing the agreement. When they write code and then write the Contract Tests last, it provides late feedback to teams regarding their contract mismatches. This means that multiple teams may need to fix their implementation of the integration code and/or update their Contract Tests, resulting in wasted time.</p></li><li><p>The Component Tests (and Contract Tests) might not be valid; they might not be testing what we expect to be testing. This is because we&#8217;ve never seen them fail. When we see passing Component Tests (and Contract Tests) it doesn&#8217;t mean anything; they might be always-green tests, which are useless. They won&#8217;t be good at detecting bugs, which means we&#8217;ll end up with a higher percentage of failing System Level Tests, thereby wasting more time debugging.</p><ul><li><p>We could partially try to handle this problem by using Code Coverage, to help us discover lines of code that are never executed by Component Tests. This is useful in helping us add some missing tests.</p></li><li><p>However, Code Coverage can&#8217;t help us know whether we&#8217;re verifying behavior - lines of code could be executed, but its output might not be asserted at all (or only partially asserted). This is where we&#8217;d need Mutation Coverage; however, the problem is that Mutation Coverage is far too slow with Component Tests (because they include I/O), hence it&#8217;s impractical.</p></li></ul></li></ul><p>Thus, in both cases, it leads to wasted time in debugging and late rework, making development more expensive.</p><h2>Approach 2. Writing Component Level Tests first</h2><p>How can we address the following problems:</p><ul><li><p>The teams faced integration issues due to misunderstandings of Contracts</p></li><li><p>The teams wrote invalid Component Level Tests, which didn&#8217;t protect them</p></li></ul><p>Let&#8217;s look at the root causes and how this can be solved with the Test First approach:</p><ul><li><p>The reason for the late integration issues is that the teams were not aligned on their inter-team contracts (or perhaps they had misunderstandings regarding behavioral decomposition). To ensure that this problem is solved, we need to convert the failing Acceptance Test into failing Component Tests (and Contract Tests) so that it specifies what behavior each Component needs to satisfy and how each Component will integrate with other Components</p></li><li><p>The reason why the Component Level Tests may be invalid with the Test Last approach is that we never saw them fail. To ensure that the tests are valid, we need to see them fail (for the right reason) before we start coding, i.e. Test First.</p></li></ul><p><strong>Problems solved with Component Level Tests first</strong></p><p>By practicing TDD at the Component Level, we help ensure that:</p><ul><li><p>The teams are aligned in decomposing the behavior of an Acceptance Test into Component Level Tests, thus minimizing/eliminating late integration issues</p></li><li><p>The teams have assurance that their tests are valid, because they saw the tests fail before implementing the code</p></li></ul><h2>TDD - Component Level - Component Tests</h2><p>Here&#8217;s an overview of TDD at the Component Level.</p><p>As we can see, for one failing Acceptance Test, we need to see apply TDD within the Component. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!apxh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!apxh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 424w, https://substackcdn.com/image/fetch/$s_!apxh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 848w, https://substackcdn.com/image/fetch/$s_!apxh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 1272w, https://substackcdn.com/image/fetch/$s_!apxh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!apxh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png" width="558" height="526.0058309037901" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:970,&quot;width&quot;:1029,&quot;resizeWidth&quot;:558,&quot;bytes&quot;:85537,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/163150286?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!apxh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 424w, https://substackcdn.com/image/fetch/$s_!apxh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 848w, https://substackcdn.com/image/fetch/$s_!apxh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 1272w, https://substackcdn.com/image/fetch/$s_!apxh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd3a8e2a1-fe1f-460c-bd4e-e9fb50c6209b_1029x970.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p>
      <p>
          <a href="https://journal.optivem.com/p/modern-tdd-component-level">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Modern Test Pyramid - Unit Level]]></title><description><![CDATA[When tests are slow, the feedback to developers is slow, and the cost of rework is high. How can we get faster feedback?]]></description><link>https://journal.optivem.com/p/modern-test-pyramid-unit-level</link><guid isPermaLink="false">https://journal.optivem.com/p/modern-test-pyramid-unit-level</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Fri, 13 Jun 2025 06:01:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/bfe2f3eb-1a7c-4cc0-a361-64138e8121fb_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128274; Welcome to the premium Optivem Journal. I&#8217;ll help you apply TDD to escape the nightmare of Legacy Code. Join our paid community of 160+ senior engineers &amp; leaders for support on your TDD journey, plus instant access to group chat and live Q&amp;As:</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Component Level Testing provides effective Developer Facing feedback. </h2><p>Component Level Testing is very useful for developers, because it provides the following:</p><ul><li><p><strong>Commit Developer Feedback:</strong> Developers don&#8217;t have to wait for the slow-running Acceptance Tests (potentially, 1hr waiting time) to get feedback whether they introduced a regression bug. With Component Level Testing, the developer can get feedback within minutes whether they broke anything with their commit.</p></li><li><p><strong>Isolated Component Developer Feedback:</strong> Developers can get feedback whether their Component works in isolation from other Components and in isolation from External Systems. This means when we see we broke our Component, we can fix it ourselves, and don&#8217;t need to bother other teams.</p><ul><li><p>The Frontend Developer can get feedback whether the Frontend works correctly in isolation (and whether it can communicate with the Backend), without actually spinning up the Backend.</p></li><li><p>The Backend Developer can get feedback whether the Backend works in isolation (and whether it can communicate with External Systems), without actually connecting to the External Systems. </p></li><li><p>In the case of Microservice Backend, the Developer can get feedback whether their Microservice works in isolation (and whether it can communicate with other Microservices), without actually spinning up the other Microservices.</p></li></ul></li></ul><h2>But is this Developer Feedback fast enough?</h2><p>Whilst Component Level testing is necessary &amp; useful, it has some limitations with the feedback loop: </p><ul><li><p><strong>Feedback is not fast enough:</strong>&nbsp;Component Tests are slow because they span I/O (e.g., a Backend Component Test involves I/O - hitting the Backend REST API, running with real DB in Testcontainers, running with WireMock/Pact to stub out external HTTP services). The more tests that there are, the more problematic this becomes. It&#8217;s challenging when there&#8217;s high business logic complexity, which can result in a large number of test cases, making the I/O slowness problem even more noticeable. This increased waiting time is a waste, it discourages us from running tests often, and reduces commit frequency. With decreased frequency of test execution, we may accumulate more regression bugs, and have to spend more time debugging.</p></li><li><p><strong>Feedback is not isolated enough:</strong> Component Tests span Presentation Logic, Business Logic, and Infrastructure Logic, so when those tests fail, we have to isolate whether the problem lies in Business Logic or Presentation/Infrastructure Logic. We don&#8217;t know, we have to debug.</p></li></ul><div><hr></div><p>&#128226; My <strong>next Live Q&amp;A Session</strong> about <strong>TDD &amp; Unit Tests </strong>is on Wed 18th Jun 17:00. </p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lu.ma/yzcvzn8u&quot;,&quot;text&quot;:&quot;Register now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://lu.ma/yzcvzn8u"><span>Register now</span></a></p><p>If you&#8217;re a Paid Member, you&#8217;ll receive 100% discount (see Event Description for instructions). If you&#8217;re a Free Member, you can upgrade now:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Solution: Unit Level Testing</h2><p>How can we get fast feedback for Business Logic, so that even if we have thousands of test cases, we can get feedback within milliseconds/seconds and not have to wait several minutes? How can we minimize the waiting time for developers? By reducing the waiting time, developers will be incentivized to run tests more often, thus commit more often. This enables developers to discover Regression Bugs ASAP, which then reduces the amount of time needed to fix the bug (since the change is still fresh in their mind). All this, combined, reduces total development time.</p><p>The Solution is:</p><ul><li><p>Unit Tests - testing Business Logic in isolation</p></li><li><p>Narrow Integration Tests - testing Presentation Logic &amp; Infrastructure Logic in isolation</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gD3J!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gD3J!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 424w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 848w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 1272w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gD3J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png" width="408" height="411.50625" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1291,&quot;width&quot;:1280,&quot;resizeWidth&quot;:408,&quot;bytes&quot;:117323,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/163150092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!gD3J!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 424w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 848w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 1272w, https://substackcdn.com/image/fetch/$s_!gD3J!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9aa633b5-3526-4cf5-b2f9-54169ef3c6e3_1280x1291.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>For a system with Frontend &amp; Monolithic Backend, we choose (separately) for Frontend and Backend whether we stay at just the Component Level or move down to the Unit Level. In the following example, we&#8217;ve chosen to stay at the Component Level for Frontend and decided to move to the Unit Level for Backend:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!v2jd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!v2jd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 424w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 848w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!v2jd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png" width="1456" height="1119" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1119,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:116045,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/163150092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!v2jd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 424w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 848w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!v2jd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F89052043-c2b8-4c13-ad1d-c60be536b716_1710x1314.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>For a system with Frontend &amp; Microservice Backend, we choose (separately) for the Frontend and each Microservice, whether we stay at the Component Level or go down to the Unit Level. In the following example, we&#8217;ve chosen to stay at the Component Level for Frontend; for microservices, for some we&#8217;ve chosen to stay at the Component Level, and for some we decided to go down to the Unit Level:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FSIM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FSIM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 424w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 848w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FSIM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png" width="1456" height="770" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:770,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:141512,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://journal.optivem.com/i/163150092?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FSIM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 424w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 848w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 1272w, https://substackcdn.com/image/fetch/$s_!FSIM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb56f05b6-78f0-4b4d-9dcc-d53a269330c6_2485x1314.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div>
      <p>
          <a href="https://journal.optivem.com/p/modern-test-pyramid-unit-level">
              Read more
          </a>
      </p>
   ]]></content:encoded></item><item><title><![CDATA[Unit Tests should NOT mirror code (Michaël Azerhad)]]></title><description><![CDATA[If your unit tests are mirroring your source code structure - one Unit Test per class, then you're doing it wrong.]]></description><link>https://journal.optivem.com/p/unit-tests-should-not-mirror-source-code-michael-azerhad</link><guid isPermaLink="false">https://journal.optivem.com/p/unit-tests-should-not-mirror-source-code-michael-azerhad</guid><dc:creator><![CDATA[Valentina Jemuović]]></dc:creator><pubDate>Wed, 11 Jun 2025 06:00:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e8a1c04d-90d0-4d7c-960e-bd2761e73722_1000x666.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>&#128075; Hello, this is Valentina with the free edition of the Optivem Journal. I&#8217;ll help you apply TDD to escape the nightmare of Legacy Code. Join our paid community of 160+ senior engineers &amp; leaders for support on your TDD journey, plus instant access to group chat and live Q&amp;As:</em></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>I highly value discussions with <a href="https://www.linkedin.com/in/michael-azerhad">Micha&#235;l Azerhad</a>, I find his writing highly resonates with my perspectives on TDD in practice. I highly recommend you follow him on LinkedIn (some posts are in French, some in English) about TDD &amp; related topics.</p><blockquote><p>&#8220;Unit does not mean &#171; unit of code &#187;, does not mean &#171; don&#8217;t traverse more than a function ; mock all neighbors &#187;, does not necessarily means "small".&#8220;</p><p>&#8230;</p><p>&#8220;A unit test describes a behaviour, a &#171; denouement &#187;, a &#171; business scenario &#187;, and therefore there must be a kind of contravariance between tests and code. <br>Unit tests do NOT mirror the code!&#8221;</p><p>- Micha&#235;l Azerhad</p></blockquote><p>There is a big confusion around Unit Testing (perhaps arising due to the Sociable Unit Tests vs Solitary Unit Tests approaches). So I collected some of Micha&#235;l&#8217;s posts below.</p><div><hr></div><p>&#128226; My <strong>next Live Q&amp;A Session</strong> about <strong>TDD &amp; Unit Tests </strong>is on <strong>Wed 18th Jun 17:00</strong>. Here are some questions I&#8217;ll be answering based on <a href="https://journal.optivem.com/chat">Group Chat</a>:</p><ol><li><p>How to deal with unit tests &amp; multithreading?</p></li><li><p>How to unit test abstract classes in libraries?</p></li><li><p>When we are testing Application Services (or Use Case Handlers) should we stub out Domain Services?</p></li><li><p>Which Test Doubles should we use in unit testing? (should we use mocking libraries or write our own test doubles)</p></li><li><p>Should we implement read methods on production repositories, just for test purposes?</p></li><li><p>How to handle non-halting errors?</p></li><li><p>Have an additional question? Add your question on <a href="https://journal.optivem.com/chat">Group Chat</a>.</p></li></ol><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://lu.ma/yzcvzn8u&quot;,&quot;text&quot;:&quot;Register now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://lu.ma/yzcvzn8u"><span>Register now</span></a></p><p>If you&#8217;re a Paid Member, you'll receive a <strong>100% discount</strong> code <em>(click on "Register now&#8221;; see Event Description for instructions)</em>. Upgrade to get the discount:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><h2>Most developers do NOT know Unit Testing</h2><p><a href="https://www.linkedin.com/in/michael-azerhad">Micha&#235;l Azerhad</a> wrote a <a href="https://www.linkedin.com/posts/michael-azerhad_unittest-quiproquo-definition-activity-7169243083836932097-x3XK/?utm_source=share&amp;utm_medium=member_ios">LinkedIn post</a> about the most crucial thing that developers still don&#8217;t know - they don&#8217;t know the meaning of unit tests. A Unit Test should describe a behavior, it should be coupled to behavior rather than being coupled to code. That&#8217;s why we should avoid one-on-one mirroring of code through tests (a mistake that many developers make, creating a unit test per source code class)</p><p>By avoiding the mirroring, this enables you to refactor code without breaking tests:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!nhRQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nhRQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 424w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 848w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 1272w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nhRQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png" width="575" height="849" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:849,&quot;width&quot;:575,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:77040,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!nhRQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 424w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 848w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 1272w, https://substackcdn.com/image/fetch/$s_!nhRQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56380dfe-7de7-4030-8c96-3d098b80dfe0_575x849.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>To learn more about the dangers of &#8220;mirroring&#8220;, read the &#8220;One-to-One Correspondence.&#8220; in Uncle Bob&#8217;s <a href="https://blog.cleancoder.com/uncle-bob/2017/03/03/TDD-Harms-Architecture.html">TDD Harms Architecture</a>.</p><blockquote><p>&#8220;Most people who are new to TDD, and the three laws, end up writing tests that look like the diagram on the left. They create a kind of one-to-one correspondence between the production code and the test code. For example, they may create a <em>test class</em> for every production code class. They may create <em>test methods</em> for every production code method.</p><p>&#8230;</p><p>The problem is &#8211; and I want you to think carefully about this next statement &#8211; <em>a one-to-one correspondence implies extremely tight coupling</em>.</p><p>&#8230;</p><p>It, frankly, took me many years to realize this. If you look at the structure of <a href="https://github.com/unclebob/fitnesse">FitNesse</a>, which we began writing in 2001, you will see a strong one-to-one correspondence between the test classes and the production code classes&#8230;.</p><p>And, of course, we experienced some of the problems that you would expect with such a sinister design. We had fragile tests. We had structures made rigid by the tests. We felt the pain of TDD. And, after several years, we started to understand that the cause of that pain was that we were not designing our tests to be decoupled.&#8221;</p><p>- Uncle Bob</p></blockquote><h2>Clarification about the word &#8220;unit&#8220; in Unit Testing</h2><p><a href="https://www.linkedin.com/in/michael-azerhad">Micha&#235;l Azerhad</a> wrote another <a href="https://www.linkedin.com/posts/michael-azerhad_tdd-unittest-history-activity-7259029681788665856-QHVC/">LinkedIn post</a> to further clarify the word &#8220;unit&#8220;, explaining the difference between Sociable and Solitary Unit Tests. In Classical TDD, Sociable Unit Tests tend to emerge:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4Rfg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4Rfg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 424w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 848w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 1272w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4Rfg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png" width="564" height="596" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:596,&quot;width&quot;:564,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:47163,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4Rfg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 424w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 848w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 1272w, https://substackcdn.com/image/fetch/$s_!4Rfg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3b8b7981-5b9d-4885-b695-5c308139b9a9_564x596.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>He further explained why we should use Sociable Unit Tests (which are coupled to behavior and may traverse multiple classes) rather than Solitary Unit Tests (which are coupled to individual classes - units of code), it&#8217;s because it enables emergent design:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xPh7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xPh7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 424w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 848w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 1272w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xPh7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png" width="570" height="311" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:311,&quot;width&quot;:570,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:28969,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!xPh7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 424w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 848w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 1272w, https://substackcdn.com/image/fetch/$s_!xPh7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F34edb119-8a6b-4040-a659-d3535c4e41fb_570x311.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Micha&#235;l explained the historical problem of the word &#8220;unit&#8220;:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4UtT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4UtT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 424w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 848w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 1272w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4UtT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png" width="581" height="836" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:836,&quot;width&quot;:581,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:237242,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4UtT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 424w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 848w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 1272w, https://substackcdn.com/image/fetch/$s_!4UtT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff514d94e-8a51-420b-bd5c-49095cb2d661_581x836.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>The following is a screenshot from Ian Cooper&#8217;s presentation:</p><blockquote><p>&#8220;I call them &#8220;unit tests&#8220;, but they don&#8217;t match the accepted definition of unit tests very well&#8221; - Kent Beck, TDD by Example</p><p>&#8220;This is the only use of the phrase &#8220;unit test&#8220; in the book, Kent is referring here to his use of the term &#8220;unit test&#8221; in casual conversation or by implication from xunit tools&#8220; - Ian Cooper</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dcAw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dcAw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 424w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 848w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dcAw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg" width="1456" height="849" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:849,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:136660,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!dcAw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 424w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 848w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!dcAw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02bb5237-1d3f-4e4d-8a11-4b148ce0ccd2_2048x1194.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><blockquote><p>&#8220;As you add new test functions to your suite, you add new behavior to your production code. Following the red-green-refactor process you extract that behavior into new functions and classes that do not require independent tests&#8220;</p><p>- Uncle Bob</p></blockquote><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7krV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7krV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7krV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7krV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7krV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7krV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg" width="1224" height="496" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:496,&quot;width&quot;:1224,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64099,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7krV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 424w, https://substackcdn.com/image/fetch/$s_!7krV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 848w, https://substackcdn.com/image/fetch/$s_!7krV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!7krV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F51337de7-2c57-46de-a359-7e27f6e185b6_1224x496.jpeg 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Don&#8217;t couple tests to structure</h2><p>I posted on <a href="https://www.linkedin.com/posts/valentinajemuovic_tdd-unittesting-softwareengineering-activity-7259472115387576320-htnq/">LinkedIn</a> to summarize this problem:</p><ul><li><p>If you write a test for every class, i.e. you&#8217;re testing every class in isolation, then your tests are mirroring your code. This structural coupling means if you change anything (e.g. move logic from one class to another, split a class, merge classes, change public interfaces of classes, etc.) then your tests will break</p></li><li><p>On the other hand, if you write a test for a &#8220;module&#8220; (it may span multiple classes), then your tests are not mirroring the code. You&#8217;re free to refactoring (change the module implementation, e.g. change the design of internal classes, their interfaces), BUT your tests won&#8217;t break</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7gfQ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7gfQ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 424w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 848w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 1272w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7gfQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png" width="565" height="526" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:526,&quot;width&quot;:565,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:55663,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7gfQ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 424w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 848w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 1272w, https://substackcdn.com/image/fetch/$s_!7gfQ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F306ef794-85eb-4e50-9475-07a0a07d1381_565x526.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c0bV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c0bV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 424w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 848w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 1272w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c0bV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png" width="574" height="731" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:731,&quot;width&quot;:574,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:198089,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c0bV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 424w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 848w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 1272w, https://substackcdn.com/image/fetch/$s_!c0bV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F737ef75d-6ccd-4ae4-8e6e-79117e033ffa_574x731.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/p/unit-tests-should-not-mirror-source-code-michael-azerhad/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://journal.optivem.com/p/unit-tests-should-not-mirror-source-code-michael-azerhad/comments"><span>Leave a comment</span></a></p><p></p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://journal.optivem.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">TDD &#183; Hexagonal Architecture &#183; Clean Architecture. Join 5K+ Engineers</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item></channel></rss>