{"id":445700,"date":"2024-02-19T14:37:55","date_gmt":"2024-02-19T13:37:55","guid":{"rendered":"https:\/\/blog.jetbrains.com\/?post_type=phpstorm&#038;p=445700"},"modified":"2025-09-17T11:42:42","modified_gmt":"2025-09-17T10:42:42","slug":"ai-for-php-how-to-tweak-ai-prompts-to-improve-php-tests","status":"publish","type":"phpstorm","link":"https:\/\/blog.jetbrains.com\/fr\/phpstorm\/2024\/02\/ai-for-php-how-to-tweak-ai-prompts-to-improve-php-tests","title":{"rendered":"AI for PHP: How to Tweak AI Prompts to Improve PHP Tests"},"content":{"rendered":"\n<p>In our <a href=\"https:\/\/blog.jetbrains.com\/fr\/phpstorm\/2024\/02\/ai-for-php-how-to-automate-unit-testing-using-ai-assistant\">previous post<\/a>, we looked at how <a href=\"https:\/\/www.jetbrains.com\/ai\/\" target=\"_blank\" rel=\"noopener\">JetBrains AI Assistant<\/a> can automatically scaffold unit tests for us. By generating the boring boilerplate code, it allows us to jump straight into the more interesting part of making our tests.<\/p>\n\n\n\n<p>Playing around with AI-driven test generation, I have often been surprised by how accurate AI Assistant is when it comes to generating code that fits within my project. However, there are cases where I\u2019d like its output to be slightly different. If only we could give it some hints about what the outcome should look like.<\/p>\n\n\n\n<p>Well, it turns out we can do precisely that.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prompt specification<\/h2>\n\n\n\n<p>Let\u2019s circle back to the example from our <a href=\"https:\/\/blog.jetbrains.com\/fr\/phpstorm\/2024\/02\/ai-for-php-how-to-automate-unit-testing-using-ai-assistant\">previous post<\/a>: We\u2019re working on tests for the <code>CreateArgumentComment<\/code> class. This class writes a record into the database, determines which users should be notified, and then sends those user notifications (using another class: <code>SendUserMessage<\/code>). Here\u2019s what that code looks like:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">final readonly class CreateArgumentComment\n{\n    public function __invoke(\n        Argument $argument,\n        User $user,\n        string $body,\n    ): void\n    {\n        ArgumentComment::create(&#091;\n            &#039;user_id&#039; =&gt; $user-&gt;id,\n            &#039;argument_id&#039; =&gt; $argument-&gt;id,\n            &#039;body&#039; =&gt; $body,\n        ]);\n\n        $this-&gt;notifyUsers($argument, $user);\n    }\n\n    private function notifyUsers(Argument $argument, User $user): void\n    {\n        $usersToNotify = $argument-&gt;comments\n            -&gt;map(fn (ArgumentComment $comment) =&gt; $comment-&gt;user)\n            -&gt;add($argument-&gt;user)\n            -&gt;reject(fn (User $other) =&gt; $other-&gt;is($user))\n            -&gt;unique(fn (User $user) =&gt; $user-&gt;id);\n\n        foreach ($usersToNotify as $userToNotify) {\n            (new SendUserMessage)(\n                to: $userToNotify,\n                sender: $user,\n                url: action(RfcDetailController::class, &#091;&#039;rfc&#039; =&gt; $argument-&gt;rfc_id, &#039;argument&#039; =&gt; $argument-&gt;id]),\n                body: &#039;wrote a new comment&#039;,\n            );\n        }\n    }\n}<\/pre>\n\n\n\n<p>You might have noticed that AI Assistant didn\u2019t write any tests for the notification part in this snippet. In fact, it did write tests for this part in <em>some<\/em> iterations, but not every time.<\/p>\n\n\n\n<p>One interesting generation included the following comment at the end of the test class:<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\">\/\/ And: we should expect the users to be notified about the comment, \n\/\/ this part is not implemented due to its complexity\n\/\/ it requires mocking dependencies and testing side effects\n\/\/ &#039;notifyUsers&#039; is private method and we can&#039;t access it directly\n\/\/ however, in real world scenario you might want to consider testing \n\/\/ it (possibly refactoring to a notification class, and testing independently)<\/pre>\n\n\n\n<p>We could, of course, ask AI Assistant to generate these tests anyway, but I actually agree with it here; <code>notifyUsers<\/code> <em>should <\/em>be a class on its own, tested in isolation. While I had initially planned to dig into the notification tests, AI Assistant has highlighted a better approach to take with them and helped me reframe my project. Thanks, AI Assistant! Since we\u2019ve decided to test <code>notifyUsers<\/code> separately, we\u2019ll set it aside and consider another use case. Imagine we want to use Mockery instead of Laravel\u2019s factories. We start by generating our tests the same way we did in the <a href=\"https:\/\/blog.jetbrains.com\/fr\/phpstorm\/2024\/02\/ai-for-php-how-to-automate-unit-testing-using-ai-assistant\">previous post<\/a>, but this time we\u2019ll spend a little more time fine-tuning AI Assistant\u2019s output.<\/p>\n\n\n\n<p>After generating a draft version of our test class, you\u2019ll notice a <em>Specify<\/em> button in the top toolbar:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/zyWRudDYaDIloN4HpHAGZmyqJrVIkQBnhP9zIj57_w44C2D51ZPnDbw4RLESIzdGTOVPiIsInfcXknJ1EahUDJcgKoGnVfyZcpFcLcHtoXC_lMWrO0Okte5rOCuObtw39ZMQfAMhy-xUr4jzEc8zpCc-1.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>This button allows you to send additional information to AI Assistant, further specifying the prompt. You could, for example, write a prompt that tells it to use Mockery like so:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/glOxGwX2kThdJZ_LCtDolb8qgxj0hxnRLzwD3kDbz6yxitz9rDvZj-mOBpqcLxUR-Ovaj11pND7Knw3SEassbbjQHUSH06MozoJLCecKvHIsLCvhMq39YSRgHmJaYWbYBc2PENu7-pB4GKQEptmoRo4-1.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>After writing this custom prompt and pressing <em>Enter<\/em>, you\u2019ll see that AI Assistant updates the code accordingly.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img decoding=\"async\" src=\"https:\/\/blog.jetbrains.com\/wp-content\/uploads\/2025\/09\/VSjiZWXFetiPQCqaGt1UBM31lC-HrElq80CUzfkQvLSpXSctwrF3pOlZDX3VQsB_i41WIMtq2imasZD3-hiS1FGvHANYx24o64-A5YI6-NIvByJpHAVjDn9-odX6GHiEoGJVw2FFrh2g2kf4o4bhe0o-1.png\" alt=\"\"\/><\/figure>\n\n\n\n<p>You can fine-tune your prompts as much as you\u2019d like, until you\u2019ve found a solution that suits your needs.<\/p>\n\n\n    <div class=\"buttons\">\n        <div class=\"buttons__row\">\n                                                <a href=\"https:\/\/www.jetbrains.com\/ai\/\" class=\"btn\" target=\"\" rel=\"noopener\">Try AI Assistant\u2019s features<\/a>\n                                                    <\/div>\n    <\/div>\n\n\n\n\n\n\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n\n\n<p>As you experiment with prompt specification, keep in mind the goal we discussed at the very beginning of this blog-post series: We\u2019re not aiming for AI Assistant to generate the perfect tests for us. We want it to do the boring boilerplate setup so that we can focus primarily on making the final tweaks \u2013 the parts that are most fun.<\/p>\n\n\n\n<p>With that in mind, I think it\u2019s important not to <em>over-specify<\/em> your prompts. It\u2019ll probably be more productive to generate code that\u2019s 90% to your liking instead of spending additional time trying to find the perfect prompt.<\/p>\n\n\n\n<p>One last side effect that you might notice is that AI Assistant actually learns from your prompts over time. For example, now that we\u2019ve specified that we would like it to use Mockery instead of Laravel factories, the tool will take that into account the next time it generates tests.<\/p>\n\n\n\n<p>If you want to learn more about how AI Assistant works under the hood and how it deals with your data, head over to the <a href=\"https:\/\/www.jetbrains.com\/legal\/docs\/terms\/jetbrains-ai-service\/\" target=\"_blank\" rel=\"noopener\">JetBrains AI Terms of Service<\/a> (section 5) to read all about it.<\/p>\n\n\n\n<p>\u2014<\/p>\n\n\n\n<p>So far in this series, we\u2019ve used AI Assistant to generate tests for us, and we\u2019ve learned how to fine-tune our prompts to get the output we need. <\/p>\n\n\n\n<p>What\u2019s the next step? PhpStorm has some pretty neat features for to combining AI Assistant with custom actions. <strong>Subscribe to our blog<\/strong> to stay updated on our upcoming posts, where we&#8217;ll continue exploring the benefits of using AI for your PHP routines.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Useful links<\/h2>\n\n\n\n<p>Did you enjoy reading this blog post? Here are more from this series:<\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/blog.jetbrains.com\/phpstorm\/2024\/02\/ai-for-php-how-to-automate-unit-testing-using-ai-assistant\/\">AI for PHP: How To Automate Unit Testing Using AI Assistant<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/blog.jetbrains.com\/phpstorm\/2024\/02\/ai-for-php-how-to-make-ai-assistant-generate-test-implementations\/\">AI for PHP: How to Make AI Assistant Generate Test Implementations<\/a><\/li>\n<\/ul>\n\n\n\n<p><strong>Resources:<\/strong><\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/blog.jetbrains.com\/fr\/phpstorm\/2024\/02\/ai-for-php-how-to-automate-unit-testing-using-ai-assistant\">AI for PHP: How To Automate Unit Testing Using AI Assistant?<\/a><\/li>\n<\/ul>\n\n\n\n<ul>\n<li><a href=\"https:\/\/www.jetbrains.com\/help\/phpstorm\/ai-assistant.html\" target=\"_blank\" rel=\"noopener\">AI Assistant in PhpStorm<\/a> (documentation)<\/li>\n\n\n\n<li><a href=\"https:\/\/www.jetbrains.com\/ai\/#plans-and-pricing\" target=\"_blank\" rel=\"noopener\">AI Assistant pricing<\/a><\/li>\n<\/ul>\n\n\n\n<p><\/p>\n\n\n\n<p><strong>Videos:<\/strong><\/p>\n\n\n\n<ul>\n<li><a href=\"https:\/\/youtu.be\/-NnYtfzO7qU?feature=shared\" target=\"_blank\" rel=\"noopener\">JetBrains AI Assistant introduction<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/youtu.be\/k8EzKJDlbFo?feature=shared\" target=\"_blank\" rel=\"noopener\">Using PHP and AI to build a Markdown to Video convertor<\/a><\/li>\n<\/ul>\n","protected":false},"author":1326,"featured_media":458468,"comment_status":"closed","ping_status":"closed","template":"","categories":[2347],"tags":[8168,8427,8337],"cross-post-tag":[8396],"acf":[],"_links":{"self":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/phpstorm\/445700"}],"collection":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/phpstorm"}],"about":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/types\/phpstorm"}],"author":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/users\/1326"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/comments?post=445700"}],"version-history":[{"count":10,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/phpstorm\/445700\/revisions"}],"predecessor-version":[{"id":620246,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/phpstorm\/445700\/revisions\/620246"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media\/458468"}],"wp:attachment":[{"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/media?parent=445700"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/categories?post=445700"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/tags?post=445700"},{"taxonomy":"cross-post-tag","embeddable":true,"href":"https:\/\/blog.jetbrains.com\/fr\/wp-json\/wp\/v2\/cross-post-tag?post=445700"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}