{"id":106,"date":"2026-07-21T09:00:00","date_gmt":"2026-07-21T09:00:00","guid":{"rendered":"https:\/\/np.themestate.com\/promptpress\/?p=106"},"modified":"2026-10-24T15:17:53","modified_gmt":"2026-10-24T15:17:53","slug":"writing-unit-tests-with-ai","status":"publish","type":"post","link":"https:\/\/demo.themnific.com\/promptpress\/writing-unit-tests-with-ai\/","title":{"rendered":"Writing Unit Tests with AI: A Prompt Pattern That Holds Up"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">AI is fast at writing tests, and that is exactly the problem. Left alone, it writes tests that <strong>confirm what the code already does<\/strong>, bugs included. The test-writing prompts in our <a href=\"\/prompts\/kind\/code\/\">code collection<\/a> use a different order: edge cases first, then tests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Below is the pattern, with a small PHP example where <strong>the edge-case step found a real bug<\/strong> before any test was written. If you haven&#8217;t set up a <a href=\"\/codebase-context-without-pasting-everything\/\">context brief<\/a> yet, do that first. Tests need to match your framework and conventions.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The pattern<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>You are writing PHPUnit tests for the function below.\n\nStep 1: List the edge cases this function should handle, including\ninputs the author may not have considered. Do not write tests yet.\nStep 2: For each edge case, state the expected result and whether\nthe current code produces it.\nStep 3: Write tests for every case. Mark tests you expect to fail\nwith a comment explaining why.\n\nFunction:\n{{code}}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">The function under test<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>function slugify( string $title ): string {\n\t$slug = strtolower( trim( $title ) );\n\t$slug = preg_replace( '\/[^a-z0-9]+\/', '-', $slug );\n\treturn trim( $slug, '-' );\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">It looks fine. Step 1 of the prompt returned a list that included one case we hadn&#8217;t thought about: <strong>non-ASCII characters<\/strong>. <code>strtolower()<\/code> doesn&#8217;t transliterate, so <em>&#8220;Caf\u00e9 Menu&#8221;<\/em> becomes <code>caf-menu<\/code>. The accented letter is silently dropped.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">The tests<\/h2>\n\n\n\n<pre class=\"wp-block-code\"><code>use PHPUnit\\Framework\\TestCase;\n\nfinal class SlugifyTest extends TestCase {\n\n\tpublic function test_converts_spaces_and_punctuation(): void {\n\t\t$this-&gt;assertSame( 'hello-world', slugify( 'Hello, World!' ) );\n\t}\n\n\tpublic function test_trims_leading_and_trailing_separators(): void {\n\t\t$this-&gt;assertSame( 'ai-prompts', slugify( '  --AI Prompts--  ' ) );\n\t}\n\n\tpublic function test_returns_empty_string_for_symbols_only(): void {\n\t\t$this-&gt;assertSame( '', slugify( '!!!' ) );\n\t}\n\n\t\/\/ Expected to fail: accented characters are dropped, not transliterated.\n\tpublic function test_keeps_accented_letters_readable(): void {\n\t\t$this-&gt;assertSame( 'cafe-menu', slugify( 'Caf\u00e9 Menu' ) );\n\t}\n}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Why the order matters<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n\n<li>Asking for edge cases first makes the model reason about <em>intended<\/em> behaviour, not current behaviour.<\/li>\n\n\n<li>Step 2 separates &#8220;what should happen&#8221; from &#8220;what happens&#8221;, which is where bugs show up.<\/li>\n\n\n<li>Marked failing tests are a to-do list, not noise.<\/li>\n\n<\/ul>\n\n\n\n<blockquote class=\"wp-block-quote is-layout-flow wp-block-quote-is-layout-flow\">\n\n<p class=\"wp-block-paragraph\">A test suite that passes on the first run should make you suspicious, not happy.<\/p>\n\n<cite>QA lead<\/cite><\/blockquote>\n\n\n\n<h2 class=\"wp-block-heading\">Keep a human in the loop<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Always run the generated tests and read the assertions. A test that asserts the wrong value is worse than no test at all. It gives you confidence you haven&#8217;t earned.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>AI-generated tests often just confirm what the code already does. This prompt pattern asks for edge cases first, and in our example it found a real bug before a single test ran.<\/p>\n","protected":false},"author":2,"featured_media":8149,"comment_status":"open","ping_status":"closed","sticky":false,"template":"template-left-sidebar.php","format":"standard","meta":{"footnotes":""},"categories":[55],"tags":[],"class_list":["post-106","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-coding-with-ai"],"_links":{"self":[{"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/posts\/106","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/comments?post=106"}],"version-history":[{"count":1,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/posts\/106\/revisions"}],"predecessor-version":[{"id":8150,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/posts\/106\/revisions\/8150"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/media\/8149"}],"wp:attachment":[{"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/media?parent=106"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/categories?post=106"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.themnific.com\/promptpress\/wp-json\/wp\/v2\/tags?post=106"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}