{"id":481,"date":"2025-08-28T10:33:17","date_gmt":"2025-08-28T10:33:17","guid":{"rendered":"https:\/\/1v0.net\/blog\/?p=481"},"modified":"2025-08-28T10:33:19","modified_gmt":"2025-08-28T10:33:19","slug":"testing-laravel-applications-with-phpunit","status":"publish","type":"post","link":"https:\/\/1v0.net\/blog\/testing-laravel-applications-with-phpunit\/","title":{"rendered":"Testing Laravel Applications with PHPUnit"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\"><strong>Testing Laravel Applications with PHPUnit<\/strong><\/h2>\n\n\n\n<p>Testing is essential for building reliable, maintainable Laravel applications. With PHPUnit integrated out of the box, you can write unit and feature tests that validate your business logic, HTTP flows, and database interactions. This guide walks through setup, writing your first tests, and understanding typical test outputs.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Setting Up PHPUnit in Laravel<\/strong><\/h2>\n\n\n\n<p>Laravel ships with PHPUnit preconfigured in <code>composer.json<\/code> under <code>require-dev<\/code>. Confirm the dependency and install vendor packages.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JSON \/ JSON with Comments\" data-shcb-language-slug=\"json\"><span><code class=\"hljs language-json\"><span class=\"hljs-string\">\"require-dev\"<\/span>: {\n    <span class=\"hljs-attr\">\"phpunit\/phpunit\"<\/span>: <span class=\"hljs-string\">\"^10.0\"<\/span>\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JSON \/ JSON with Comments<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">json<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This ensures PHPUnit is available to Laravel\u2019s test runner. If you\u2019re upgrading, run <code>composer update<\/code> to get the right version for your PHP\/Laravel stack.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">composer install\nphp artisan <span class=\"hljs-built_in\">test<\/span><\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>The first run should execute the default example test and report results in a readable, colored format.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Creating Your First Unit Test<\/strong><\/h2>\n\n\n\n<p>Use Artisan to scaffold a unit test class. Unit tests focus on small, isolated pieces of logic without the framework bootstrapping overhead.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">php artisan make:<span class=\"hljs-built_in\">test<\/span> UserMathTest --unit<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Open the generated file at <code>tests\/Unit\/UserMathTest.php<\/code> and add a simple assertion.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">Tests<\/span>\\<span class=\"hljs-title\">Unit<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">PHPUnit<\/span>\\<span class=\"hljs-title\">Framework<\/span>\\<span class=\"hljs-title\">TestCase<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">UserMathTest<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">TestCase<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">test_basic_math_addition<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        <span class=\"hljs-keyword\">$this<\/span>-&gt;assertSame(<span class=\"hljs-number\">4<\/span>, <span class=\"hljs-number\">2<\/span> + <span class=\"hljs-number\">2<\/span>);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This basic test verifies your PHPUnit setup. It runs quickly and proves your environment is configured correctly.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Writing a Feature Test (HTTP + Database)<\/strong><\/h2>\n\n\n\n<p>Feature tests exercise full request lifecycles, including routes, controllers, middleware, and the database. Let\u2019s test a simple \u201ccreate post\u201d flow.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">php artisan make:<span class=\"hljs-built_in\">test<\/span> PostCreationTest<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Update <code>tests\/Feature\/PostCreationTest.php<\/code> to validate the HTTP response and database changes.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">namespace<\/span> <span class=\"hljs-title\">Tests<\/span>\\<span class=\"hljs-title\">Feature<\/span>;\n\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Tests<\/span>\\<span class=\"hljs-title\">TestCase<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">Illuminate<\/span>\\<span class=\"hljs-title\">Foundation<\/span>\\<span class=\"hljs-title\">Testing<\/span>\\<span class=\"hljs-title\">RefreshDatabase<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>\\<span class=\"hljs-title\">User<\/span>;\n<span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">App<\/span>\\<span class=\"hljs-title\">Models<\/span>\\<span class=\"hljs-title\">Post<\/span>;\n\n<span class=\"hljs-class\"><span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title\">PostCreationTest<\/span> <span class=\"hljs-keyword\">extends<\/span> <span class=\"hljs-title\">TestCase<\/span>\n<\/span>{\n    <span class=\"hljs-keyword\">use<\/span> <span class=\"hljs-title\">RefreshDatabase<\/span>;\n\n    <span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">test_authenticated_user_can_create_post<\/span><span class=\"hljs-params\">()<\/span>\n    <\/span>{\n        $user = User::factory()-&gt;create();\n\n        $response = <span class=\"hljs-keyword\">$this<\/span>-&gt;actingAs($user)\n            -&gt;post(<span class=\"hljs-string\">'\/posts'<\/span>, &#91;\n                <span class=\"hljs-string\">'title'<\/span> =&gt; <span class=\"hljs-string\">'My First Post'<\/span>,\n                <span class=\"hljs-string\">'body'<\/span>  =&gt; <span class=\"hljs-string\">'Hello world!'<\/span>,\n            ]);\n\n        $response-&gt;assertRedirect(<span class=\"hljs-string\">'\/posts'<\/span>);\n        <span class=\"hljs-keyword\">$this<\/span>-&gt;assertDatabaseHas(<span class=\"hljs-string\">'posts'<\/span>, &#91;\n            <span class=\"hljs-string\">'title'<\/span> =&gt; <span class=\"hljs-string\">'My First Post'<\/span>,\n        ]);\n    }\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This test signs in a user, posts form data, expects a redirect, and verifies that the record exists. For production-grade examples of auth flows, also see <a href=\"\/blog\/how-to-build-email-verification-in-laravel-12-step-by-step\">How to Build Email Verification in Laravel 12 (Step by Step)<\/a> and <a href=\"\/blog\/implementing-password-reset-in-laravel-12-without-packages\">Implementing Password Reset in Laravel 12 Without Packages<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Running Tests and Filtering by Class\/Method<\/strong><\/h2>\n\n\n\n<p>Run the entire test suite, a single class, or even a single method using filters.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\"><span class=\"hljs-comment\"># run all tests<\/span>\nphp artisan <span class=\"hljs-built_in\">test<\/span>\n\n<span class=\"hljs-comment\"># run a specific class<\/span>\nphp artisan <span class=\"hljs-built_in\">test<\/span> --filter=PostCreationTest\n\n<span class=\"hljs-comment\"># run a specific test method<\/span>\nphp artisan <span class=\"hljs-built_in\">test<\/span> --filter=PostCreationTest::test_authenticated_user_can_create_post<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Filtering speeds up the feedback loop while you iterate on a failing scenario.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Sample Output from <code>php artisan test<\/code><\/strong><\/h2>\n\n\n\n<p>Here\u2019s a typical output when all tests pass. Your numbers will differ based on how many tests\/asser\u00adtions you have.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"Bash\" data-shcb-language-slug=\"bash\"><span><code class=\"hljs language-bash\">PHPUnit 10.*\/Laravel Test Runner\n\n   PASS  Tests\\Unit\\UserMathTest\n  \u2713 test_basic_math_addition\n\n   PASS  Tests\\Feature\\PostCreationTest\n  \u2713 test_authenticated_user_can_create_post\n\n  Tests:  2 passed\n  Assertions: 3\n  Time: 0.58s<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">Bash<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">bash<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>When a test fails, the output highlights the failing assertion, expected vs actual values, and a snippet of the stack trace to help you navigate the source quickly.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Seeding, Factories, and Faster Test Data<\/strong><\/h2>\n\n\n\n<p>Use model factories and seeders to generate realistic test data quickly. This keeps tests readable and reduces duplication across scenarios.<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-comment\">\/\/ Example: creating many posts for a listing test<\/span>\n$posts = \\App\\Models\\Post::factory()-&gt;count(<span class=\"hljs-number\">10<\/span>)-&gt;create();<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>Factories keep your tests expressive and focused on behavior. For deeper coverage, see <a href=\"\/blog\/using-laravel-factories-seeders-for-test-data\">Using Laravel Factories and Seeders for Test Data<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>UI-Related Testing Tips<\/strong><\/h2>\n\n\n\n<p>For Blade-driven UIs, test the rendered output and important view data. Focus on what matters (HTTP status, redirected routes, session flashes, and presence of key strings).<\/p>\n\n\n<pre class=\"wp-block-code\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php\"><span class=\"hljs-keyword\">public<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">test_posts_index_renders_titles<\/span><span class=\"hljs-params\">()<\/span>\n<\/span>{\n    $posts = \\App\\Models\\Post::factory()-&gt;count(<span class=\"hljs-number\">2<\/span>)-&gt;create(&#91;\n        <span class=\"hljs-string\">'title'<\/span> =&gt; <span class=\"hljs-string\">'Visible In List'<\/span>\n    ]);\n\n    $response = <span class=\"hljs-keyword\">$this<\/span>-&gt;get(<span class=\"hljs-string\">'\/posts'<\/span>);\n\n    $response-&gt;assertOk()\n        -&gt;assertSee(<span class=\"hljs-string\">'Visible In List'<\/span>);\n}<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n\n\n<p>This checks that the index page renders properly and contains expected text. For browser-level interactions (clicks, JS), consider <a href=\"\/blog\/how-to-use-laravel-dusk-for-browser-testing\">How to Use Laravel Dusk for Browser Testing<\/a>.<\/p>\n\n\n\n<div class=\"wp-block-spacer\" style=\"height:100px\" aria-hidden=\"true\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>Wrapping Up<\/strong><\/h2>\n\n\n\n<p>You learned how to confirm your PHPUnit setup, create unit and feature tests, filter test runs, read outputs, and leverage factories for fast data setup. A disciplined testing habit yields fewer regressions and more confidence when refactoring.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\"><strong>What\u2019s Next<\/strong><\/h2>\n\n\n\n<p>Continue strengthening your test suite with these related guides:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"\/blog\/how-to-write-feature-tests-in-laravel-for-apis\">How to Write Feature Tests in Laravel for APIs<\/a><\/li>\n<li><a href=\"\/blog\/using-laravel-factories-seeders-for-test-data\">Using Laravel Factories and Seeders for Test Data<\/a><\/li>\n<li><a href=\"\/blog\/how-to-use-laravel-dusk-for-browser-testing\">How to Use Laravel Dusk for Browser Testing<\/a><\/li>\n<\/ul>\n\n","protected":false},"excerpt":{"rendered":"<p>Testing Laravel Applications with PHPUnit Testing is essential for building reliable, maintainable Laravel applications. With PHPUnit integrated out of the box, you can write unit and feature tests that validate your business logic, HTTP flows, and database interactions. This guide walks through setup, writing your first tests, and understanding typical test outputs. Setting Up PHPUnit [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":486,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[85,86,87],"class_list":["post-481","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-laravel","tag-automation","tag-phpunit","tag-testing"],"_links":{"self":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/481","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/comments?post=481"}],"version-history":[{"count":1,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/481\/revisions"}],"predecessor-version":[{"id":485,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/posts\/481\/revisions\/485"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media\/486"}],"wp:attachment":[{"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/media?parent=481"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/categories?post=481"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/1v0.net\/blog\/wp-json\/wp\/v2\/tags?post=481"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}