Summer Sale! All accounts are 50% off this week.

caesargustav's avatar

Co-locate tests with belonging features

Hello everybody!

I want to structure my app using "Modules". The reason for that is, that the application grew a lot in the last months and it became hard to maintain all parts because sometimes you couldn't directly see all parts.

So i went from this:

App
	Controllers
		Invoice
			InvoiceController
		Jobs
			Invoice
				InvoiceJob1
				InvoiceJob2
		...
Tests
	Unit
		InvoiceTest

To this:

App
	Modules
		Invoice
			Controllers
				InvoiceController
			Jobs
				InvoiceJob1
				InvoiceJob2
			Tests
				Unit
					InvoiceTest
Tests
TestCase.php

The repetition of directories like "Controllers", "Jobs" is much less confusing than before, in my opinion.

This all works great in development.

In my phpunit.xml file I made the following change to make module tests work:

    <testsuites>
        <testsuite name="Application">
            <directory suffix="Test.php">./tests</directory>
        </testsuite>
        <testsuite name="Modules">
            <directory suffix="Test.php">./app/Modules/*</directory>
        </testsuite>
    </testsuites>

But in production everything breaks because of Composers autoloader. I configured the app folder as PSR-4 namespace. This results in the autoloader trying to load all classes from the Tests folder as well. This fails, because of this part in composer.json, because it can't find the class TestCase

    "autoload-dev": {
        "psr-4": {
            "Tests\": "tests/"
        }
    },

I tried moving it to autoload but this fails also, because then the overlying PHPUnitTestCase is not found (which makes sense since in production I'm using composer with the --no-dev flag).

I also tried using exclude-from-classmap but my understanding is, this only works when using the classmap property and not psr-4:

    "autoload": {
        "psr-4": {
            "App\": "app/",
            "Database\Seeders\": "database/seeders/"
        },
        "exclude-from-classmap": [
            [
                "app/Modules/**/Tests/"
            ]
        ]
    },

For now we just installed the dev-dependencies for production. But that's not optimal and slows down our application.

Did anyone also structure their app like this and solve this?

0 likes
1 reply
LaryAI's avatar
Level 58

It sounds like you are running into an issue with the autoloader not being able to find the TestCase class in production. One possible solution is to use the classmap property in your composer.json file instead of psr-4. This will allow you to specify the exact location of the TestCase class and exclude the modules tests from the autoloader.

For example:

"autoload": {
    "classmap": [
        "app/Modules/**/Tests/TestCase.php",
        "app/Modules/**/Controllers/*.php",
        "app/Modules/**/Jobs/*.php"
    ],
    "exclude-from-classmap": [
        "app/Modules/**/Tests/*.php"
    ]
},

This should allow the autoloader to find the TestCase class while excluding the other tests from being loaded.

Please or to participate in this conversation.