How to make PHPUnit test in a Module? I'm not very much knowledgeable about making PHPUnit and Drupal testing setup.

I am having problems regarding database calls.

I tried to setup phpunit test.

Inside my module/some_module. I installed phpunit by running

composer require --dev phpunit/phpunit ^8


This is my module/some_module/composer.json

{
    "autoload": {
        "classmap": [
            "src/"
        ]
    },
    "require-dev": {
        "phpunit/phpunit": "^8"
    }
}


This is my module/some_module/tests/SampleTest.php

&lt;?php

use PHPUnit\Framework\TestCase;
use Drupal\nat\Controller\SampleController;
use Drupal\Core\Controller\ControllerBase;

final class SampleTest extends TestCase
{
    public function testCanFilterData(): void
    {
        $this-&gt;getMockBuilder(ControllerBase::class)
            -&gt;getMock();

        $class = new ReflectionClass(SampleController::class);
        $method = $class-&gt;getMethod('filterData');
        $method-&gt;setAccessible(true);

        $obj = new SampleController();
        $args = [1, 2, 3];
        $method-&gt;invokeArgs($obj, [$args]);

        print_r($foo);
    }
}


This is my module/some_module/src/Controller/SampleController.php

&lt;?php

namespace Drupal\some_module\Controller;

use Drupal\Core\Controller\ControllerBase;

class SampleController extends ControllerBase {
    public function index()
    {
        $ids = [1, 2, 3]
        $data = [];

        $data['some_data'] = $this-&gt;filterData($ids);

        return [*
            '#theme' =&gt; 'test_template',
            '#data' =&gt; $data,
          ];
    }

    private function filterData($ids)
    {
        $connection = \Drupal::database();
        $query = $connection-&gt;query("SELECT
                id, name
            FROM products
            WHERE id IN (:ids[])",
            [
                ':ids[]' =&gt; $ids,
            ]
        );

        return $query-&gt;fetchAll(\PDO::FETCH_ASSOC);
    }
}


When I ran phpunit tests/NatTest.php, I am getting this error:

1) NatTest::testCanBeCreatedFromValidEmailAddress
Error: Class 'Drupal' not found


So my question is how can I test this? I can't mock Drupal because I actually want to execute a database query from Drupal. How can I do this?
Automated tests describes the different tests and makes clear which test should be used, in a Drupal environment. In particular, it says:


Unit tests: Test functionality of a class if the Drupal environment (database, settings, etc.) and web browser are not needed for the test, or if the Drupal environment can be replaced by a "mock" object.
Kernel tests: Test functionality of a class if the full Drupal environment and web browser are not needed for the test, but the functionality has significant Drupal dependencies that cannot easily be mocked. Kernel tests can access services, the database, and a minimal mocked file system, and they use an in-memory pseudo-installation. However, modules are only installed to the point of having services and hooks, unless you install them explicitly.


If you are testing a class that should insert data in the database, the test should be a Kernel test, which means:


The base class of the test should be \Drupal\KernelTests\KernelTestBase
The namespace of the test should start with (in your case) \Drupal\Tests\some_module\Kernel, and it should be placed in the some_module/tests/src/Kernel directory or a sub-directory


For example, the DatabaseBackendTagTest class implements a Kernel test that accesses the database.

  public function testTagInvalidations() {
    // Create cache entry in multiple bins.
    $tags = [
      'test_tag:1',
      'test_tag:2',
      'test_tag:3',
    ];
    $bins = [
      'data',
      'bootstrap',
      'render',
    ];
    foreach ($bins as $bin) {
      $bin = \Drupal::cache($bin);
      $bin-&gt;set('test', 'value', Cache::PERMANENT, $tags);
      $this-&gt;assertTrue($bin-&gt;get('test'), 'Cache item was set in bin.');
    }
    $connection = Database::getConnection();
    $invalidations_before = intval($connection-&gt;select('cachetags')-&gt;fields('cachetags', ['invalidations'])-&gt;condition('tag', 'test_tag:2')-&gt;execute()-&gt;fetchField());
    Cache::invalidateTags(['test_tag:2']);

    // Test that cache entry has been invalidated in multiple bins.
    foreach ($bins as $bin) {
      $bin = \Drupal::cache($bin);
      $this-&gt;assertFalse($bin-&gt;get('test'), 'Tag invalidation affected item in bin.');
    }


The code shown in the question just reads data from the database. (I don't see code writing the database.) Keep in mind that the database used from tests isn't automatically populated; if the purpose of the test is verifying the controller outputs the correct data, the database table needs to be filled with the data. That is normally done from the setUp() method, which could also initialize a property with the connection (for example with $this-&gt;connection = Database::getConnection();) if the data is the same for each test, or at the beginning of the test method, if each test needs different data. (For example, testCanFilterData() could test the controller filter the data in the database and testCanFilterWrongData() could test the controller doesn't output completely wrong data or out-of-the-set data.)