12

I'm trying to get my head around PHP namespaces and testing with PHPUnit.

These tests from Codewars pass when I run phpunit test.php in the command line on Windows:

<?php
require 'solution.php';
use PHPUnit\Framework\TestCase;

class myTests extends TestCase {
  public function testExamples() {
        $this->assertEquals(pair_sum([1,9,2,8,3,7,4,6,5,5,13,14,11,13,-1],10),6);
        $this->assertEquals(pair_sum([1,2,3,1],3),1);
        $this->assertEquals(pair_sum([1,3,2,2],4),2);
        $this->assertEquals(pair_sum([1],4),false);
        $this->assertEquals(pair_sum([2,3,10,-5],5),2);
  }
}

However, when I comment out use PHPUnit\Framework\TestCase; I get Class 'TestCase' not found which makes sense since there is no reference to the needed classes/functions.

What's confusing me though is that lots of answers here on SO about namespacing claim that the use keyword is NOT a substitute for include/require and that the classes still need to be included/autoloaded(?).

I'm not using any autoloading here - just a solution.php file and the tests above in a test.php file.

Can someone please explain what I'm missing here? How come the tests work without any explicit including of the PHPunit functionality?

I should mention that I have PHPUnit installed globally via Composer.

Robin Andrews
  • 3,514
  • 11
  • 43
  • 111
  • 1
    There is no `Use vs Include in PHP` if you want to use `use` in the right way, you have to work with an `autoloader` for loading the class. – JustOnUnderMillions Mar 31 '17 at 11:32
  • 1
    And `use` is for getting an shorthand in the current script. That has nothing to do with include. You can also do `class myTests extends \PHPUnit\Framework\TestCase {` – JustOnUnderMillions Mar 31 '17 at 11:34
  • 2
    You run that file through `phpunit`, which has already loaded all the relevant PHPUnit files. `use` didn't load the file, `phpunit` did. – deceze Mar 31 '17 at 11:35
  • http://stackoverflow.com/questions/43136277/how-and-where-should-i-use-the-keyword-use-in-php/43136659#43136659 – M A SIDDIQUI Mar 31 '17 at 11:39
  • 1
    `Can someone please explain what I'm missing here?` @deceze hits the nail. Scripts running via `phpunit` are not working as in `php`. – JustOnUnderMillions Mar 31 '17 at 11:43
  • So when phpunit runs, does it autoload its own classes based on `use` statements, including the one in my `test.php` file? – Robin Andrews Mar 31 '17 at 11:47
  • `phpunit` `require`s a bunch of files, which then happen to be loaded already by the time your code is executed, so you don't have to load them. Whether `phpunit` uses `use` anywhere is beside the point. – deceze Mar 31 '17 at 12:03
  • Thanks everyone for trying to help me understand. I'm still asking myself if this `use` statement is so apparently "weak," how come my tests don't run when I comment it out? – Robin Andrews Mar 31 '17 at 13:08
  • Because if you comment it out, `extends TestCase` refers to `TestCase` (global) which doesn't exist, not the required `PHPUnit\Framework\TestCase`. – deceze Mar 31 '17 at 13:34

4 Answers4

7

To make namespaces clear (ignore load of the class file here)

So in one php-file:

namespace xyz {
  class a {}
  class b {}
}
namespace abc {
  use xyz\a;
  new a();
  new \xyz\b();
  class b extends a {}
}
namespace {
 use abc\b as aa;
 use xyz\b as bb;
 new bb;
 new aa;
}

Namespace are for preventing name-conflicts!

JustOnUnderMillions
  • 3,741
  • 9
  • 12
4

use doesn't include anything. It just imports the specified namespace (or class) to the current scope, you need to have an autoloader set up in order to include the file in which the namespace is defined. Read more about autoloading here:http://php.net/manual/en/language.oop5.autoload.php

The include statement includes and evaluates the specified file.

Example:

<?php

$color = 'green';
$fruit = 'apple';

?>

test.php
<?php

echo "A $color $fruit"; // A

include 'vars.php';

echo "A $color $fruit"; // A green apple

?>
Shakti Phartiyal
  • 6,156
  • 3
  • 25
  • 46
  • 3
    *"imports the specified namespace to the current scope"* - it doesn't even do that. All it does is establish an *alias*, a shorthand you can use in your code. Nothing more. – deceze Mar 31 '17 at 11:43
4

Like @deceze said, the PHPUnit did the job for you, but don't think that use will not require the file included.

Look with atention to the structure: https://phpunit.de/manual/current/en/database.html#database.tip-use-your-own-abstract-database-testcase

PRO-TIP: Open the phpunit files that you'll understand better.

capcj
  • 1,535
  • 1
  • 16
  • 23
1

use can be usually used to shorten a Class names, when it is put at the top of class definition. But when use occurs inside a class definition, then it meant to include a Trait. https://www.w3schools.com/php/php_oop_traits.asp

tenzin
  • 75
  • 7