47
votes

I'm starting to write PHPUnit tests and I'd like the tests to be run from developers machines as well as from our servers. Developers machines are set up differently than the servers and even differently from each other.

To run in these different places it seems to be the person that runs the test is going to have to indicate where it's being run. The test can then look up the proper config of the machine it's running on.

I'm imagining something like:

phpunit.bat -X johns_laptop unittest.php

or on the alpha server:

phpunit -X alpha unittest.php

In the test I would be able to get the value if the 'X' (or whatever it is) parameter and know, for example, what the path to the app root is for this machine.

It doesn't look like the command line allows for that - or have I missed something?

10

10 Answers

32
votes

One way would be for you to inspect $argv and $argc. Something like:

<?php

require_once 'PHPUnit/Framework/TestCase.php';

class EnvironmentTest extends PHPUnit_Framework_TestCase {
    public function testHasParam() {
            global $argv, $argc;
            $this->assertGreaterThan(2, $argc, 'No environment name passed');
            $environment = $argv[2];
    }
}

Then you can call your phpunittest like this:

phpunit EnvironmentTest.php my-computer
44
votes

You can use PHPUnit's --bootstrap switch for this.

--bootstrap <file>       A "bootstrap" PHP file that is run before the tests.

Then, make a bootstrap.php file that contains variables:

$port = 4445;

In your tests, you can grab those values:

global $port;
$this->setPort($port);

Then run:

phpunit --bootstrap boot.php MyTest.php
16
votes

An elegant way to pass variables to both bootstrap files as well as to test files is by using environment variables:

export MY_ENV_VAR="some value"

phpunit all

Then, in your PHP files, you can access it like this:

getenv('MY_ENV_VAR')

Source: http://blog.lysender.com/2010/10/phpunit-passing-environment-variable-to-your-application/

5
votes

As Jasir already mentioned, a one line solution would be to set environment variable before phpunit call.

On Linux:

X=alpha phpunit unittest.php

On Windows probably:

set X=johns_laptop && phpunit.bat unittest.php

And inside your script use

getenv('X')

to read the value

4
votes

I don't think answers above solve my same problem.

The accepted answer is not perfect. In this way, custom options should always be put to the end of the parameters list, and there is no indicator to tell that they are custom options. If the number of custom options which I need is not fixed, I should code a lot to parse custom options with regular expressions or something like that.

The environment variables solution is good, but not natural. Looks weird.

VAR1=aaa VAR2=bbb VAR3=ccc ./phpunit-custom-option CustomOptionTest.php

The shell script plus setUp() solution share the same weakness with the accepted one. May be you should code a lot to parse the file and handle unpredictable numbers of custom options.

I don't think the bootstrap script is the correct solution. It could be used to handle dirty works automatically, with doing same things every time but not dealing with change parts good.

I don't like all the above answers.

And I have no good idea myself too. But maybe what I've done could give you inspiration. I've forked the phpunit project on GitHub, and modified code a little, and made it to support the custom option feature.

enter image description here

Modified version of phpunit, could accept custom options like this:

./phpuint-custom-option --custom var1=value1 --custom var2=value2 CustomOptionTest.php

And in the test, you can visit the custom options by accessing the super global variables $_SERVER

<?php

class CustomOptionTest extends PHPUnit_Framework_TestCase {

    public function testCustomOption() {
        $this->assertEquals('value1', $_SERVER['var1']);
        $this->assertEquals('value2', $_SERVER['var2']);
    }
}

and you can find my code here, and download the modified version here (by click the "view the full file" link on the page).

FYI. this article is the similar solution.

2
votes

I struggled with this exact issue, and came up with a kind of hacky-yet-convenient solution: I write parameters to a file on disk and retrieve them in the setUp() method:

public function setUp() {
    $this->setBrowser('firefox');
    $this->base_url = file_get_contents("selenium_host");
    $this->setBrowserUrl($this->base_url);
}

Rather than calling phpunit or paratest directly, I have a shell script to launch the tests. This one invokes paratest and lets me specify the number of processes as well as the host I'd like the tests to run against.

run_all_tests.sh

if [ $1 ] 
then
    threads=$1
else
    threads=5
fi
if [ $2 ]
then
    echo $2 > selenium_host
else
    echo 'http://defaulthost.com' > selenium_host
fi

vendor/bin/paratest -p$threads -f --colors TestSuite.php

Then, to run with 7 threads against http://adifferenthost.com:

./run_all_tests.sh 7 'http://adifferenthost.com'

2
votes

All the solutions here are valid for the question, but there is yet another way that might be simpler for some situations. Phing will take arguments passed in the form -Dargument=value

So using phing -Dtest=MyTest.class.php

You can then use phing conditionals to handle these arguments:

<if>
    <isset property="test" />
    <then>
        <property name="testFile" value="${test}" />
    </then>
    <else>
        <property name="testFile" value="AllTests.php" />
    </else>
</if>
<exec command="phpunit --bootstrap myTestFile/bootstrap.php- myTestFolder/${testFile}"
      passthru="true" returnproperty="phpunitreturn" />
1
votes

Passing arguments on the command line would make sense if you want to vary the test parameters per test run. Running host-specific tests on different machines is not the best justification for this solution.

For that, the PHPUnit configuration file may prove to be more suitable. It gives you control over host- and even request-specific variables including manipulating php.ini settings as well as defining constants, global variables, $_ENV, $_SERVER, and even $_GET, $_POST, etc. This is all done under the <php> node of the configuration file, see Setting PHP INI settings, Constants and Global Variables

Symfony2 uses this approach and provides both a phpunit.xml.dist (default config) and a phpunit.xml with your unit tests. The latter is gitignored to allow you to customize it for each machine without affecting the repo. You would then run your tests with:

phpunit -c /path/to/phpunit.xml
0
votes

No need of environment variables nor special scripts. You can use -d option to set php.ini values.

<?php // tests/IniTest.php
use PHPUnit\Framework\TestCase;

class IniTest extends TestCase
{
  public $server;

  public function setUp(): void
  {
    $this->server = ini_get('my.custom.server') ?: '127.0.0.1'; // fallback
  }

  public function testDummy()
  {
    $this->assertIsString($this->server);
  }
}

Execute the code like this:

vendor/bin/phpunit -d my.custom.server=192.168.1.15 tests/IniTest.php

Setting custom php.ini values is valid. For example you can configure a PDO connection alias with pdo.dsn.*. https://www.php.net/manual/en/pdo.construct.php

-1
votes

If you would like to run tests on remote machine, use ssh then run it. On locale machine you only have to cd to your root dir, then run phpunit.

user@local:/path/to/your/project$ phpunit
user@remote:/var/www/project$ phpunit

Edit: You are talking about a machine dependent configuration. (What kind of conf btw?) My solution is to put these config under the same, not versioncontrolled place, then read/parse it runtime, in the needed set up methds for example.