Drazisil
Drazisil

Reputation: 3373

phpunit: How do I pass values between tests?

I'm really running into a brick wall with this. How do you pass class values between tests in phpunit?

Test 1 -> sets value,

Test 2 -> reads value

Here is my code:

class JsonRpcBitcoinTest extends PHPUnit_Framework_TestCase
{
    public function setUp(){
        global $configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort;

        $this->bitcoindConn = new JsonRpcBitcoin($configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort);
        $this->blockHash = '';
    }

    /**
    * @depends testCanAuthenticateToBitcoindWithGoodCred
    */
    public function testCmdGetBlockHash()
    {   
        $result = (array)json_decode($this->bitcoindConn->getblockhash(20));
        $this->blockHash = $result['result'];
        $this->assertNotNull($result['result']);
    }

    /**
    * @depends testCmdGetBlockHash
    */
    public function testCmdGetBlock()
    {   
        $result = (array)json_decode($this->bitcoindConn->getblock($this->blockHash));
        $this->assertEquals($result['error'], $this->blockHash);
    }
}

testCmdGetBlock() is not getting the value of $this->blockHash that should be set in testCmdGetBlockHash().

Help in understanding what is wrong would be greatly appreciated.

Upvotes: 35

Views: 24513

Answers (6)

The Schwartz
The Schwartz

Reputation: 767

You can use a static variable using the method setUpBeforeClass:

protected static $sharedId;

public static function setUpBeforeClass(): void
{
    self::$sharedId = random_int(100,10000);
}

And access it in you tests like this:

public function testCreateLocation() {
    echo 'Shared variable = ' . self::$sharedId;
    // Use the variable in your test code and asserts...

}

/The Schwartz

Upvotes: 1

Marco Floriano
Marco Floriano

Reputation: 349

Another (simpler) example using static variables as pointed out by Boštjan Biber:

class ClientTest extends \PHPUnit\Framework\TestCase
{
    protected $client;
    protected static $testClient;

    // Before a test method is run, a template method called setUp() is invoked.
    public function setUp() :void
    {
        $this->client = new \Application\models\Clients;
    }

    public function testInsertCustomer()
    {
        $testclient = array(
            'name' => 'Test Client',
            'responsible' => 'Responsible Test',
            'payment' => 'Test payment',
            'email' => 'Test Email',
            'phone' => '123-456-789'
        );
        $this->assertTrue($this->customer->insertCustomer($CustomerTest));
    }

    public function testGetCustomers()
    {
        $this->assertIsArray($this->customer->getCustomers());
        $this->assertNotEmpty($this->customer->getCustomers());
        // Save test client for other methods
        $clients = $this->client->getClients();
        static::$testCustomer = end($customers);
    }

    public function testGetClient()
    {
        $this->assertIsArray($this->customer->getCustomer(static::$customerTest['customer_id']));
        $this->assertNotEmpty($this->customer->getCustomer(static::$customerTest['customer_id']));
    }
}

Upvotes: 0

Boštjan Biber
Boštjan Biber

Reputation: 502

Another option is to use static variables.

Here is an example (for Symfony 4 functional tests):

namespace App\Tests\Controller\Api;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Hautelook\AliceBundle\PhpUnit\RefreshDatabaseTrait;
use Symfony\Component\HttpFoundation\AcceptHeader;

class BasicApiTest extends WebTestCase
{
    // This trait provided by HautelookAliceBundle will take care of refreshing the database content to a known state before each test
    use RefreshDatabaseTrait;

    private $client = null;

    /**
     * @var string
     */
    private const APP_TOKEN = 'token-for-tests';

    /**
     * @var string
     */
    private static $app_user__email = 'tester+api+01@localhost';

    /**
     * @var string
     */
    private static $app_user__pass = 'tester+app+01+password';

    /**
     * @var null|string
     */
    private static $app_user__access_token = null;

    public function test__Authentication__Login()
    {
        $this->client->request(
            Request::METHOD_POST,
            '/api/login',
            [],
            [],
            [
                'CONTENT_TYPE' => 'application/json',
                'HTTP_App-Token' => self::APP_TOKEN
            ],
            '{"user":"'.static::$app_user__email.'","pass":"'.static::$app_user__pass.'"}'
        );
        $response = $this->client->getResponse();

        $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());

        $content_type = AcceptHeader::fromString($response->headers->get('Content-Type'));
        $this->assertTrue($content_type->has('application/json'));

        $responseData = json_decode($response->getContent(), true);
        $this->assertArrayHasKey('token', $responseData);

        $this->static = static::$app_user__access_token = $responseData['token'];
    }

    /**
     * @depends test__Authentication__Login
     */
    public function test__SomeOtherTest()
    {
        $this->client->request(
            Request::METHOD_GET,
            '/api/some_endpoint',
            [],
            [],
            [
                'CONTENT_TYPE' => 'application/json',
                'HTTP_App-Token' => self::APP_TOKEN,
                'HTTP_Authorization' => 'Bearer ' . static::$app_user__access_token
            ],
            '{"user":"'.static::$app_user__email.'","pass":"'.static::$app_user__pass.'"}'
        );
        $response = $this->client->getResponse();

        $this->assertEquals(Response::HTTP_OK, $response->getStatusCode());

        $content_type = AcceptHeader::fromString($response->headers->get('Content-Type'));
        $this->assertTrue($content_type->has('application/json'));
        //...
    }
}

Upvotes: 2

ShaunOReilly
ShaunOReilly

Reputation: 2206

This worked for me perfectly fine across all tests: $this->varablename

class SignupTest extends TestCase
{
    private $testemail = "[email protected]";
    private $testpassword = "Mypassword";
    public $testcustomerid = 123;
    private $testcountrycode = "+1";
    private $testphone = "5005550000";

    public function setUp(): void
    {
        parent::setUp();
    }

    public function tearDown(): void 
    {
        parent::tearDown();
    }

    public function testSignup()
    {
        $this->assertEquals("5005550000", $this->testphone;
    }
}

Upvotes: -1

Anonymous
Anonymous

Reputation: 12100

The setUp() method is always called before tests, so even if you set up a dependency between two tests, any variables set in setUp() will be overwritten. The way PHPUnit data passing works is from the return value of one test to the parameter of the other:

class JsonRpcBitcoinTest extends PHPUnit_Framework_TestCase
{
    public function setUp()
    {
        global $configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort;

        $this->bitcoindConn = new JsonRpcBitcoin($configRpcUser, $configRpcPass, $configRpcHost, $configRpcPort);
        $this->blockHash = '';
    }


    public function testCmdGetBlockHash()
    {   
        $result = (array)json_decode($this->bitcoindConn->getblockhash(20));
        $this->assertNotNull($result['result']);

        return $result['result']; // the block hash
    }


    /**
     * @depends testCmdGetBlockHash
     */
    public function testCmdGetBlock($blockHash) // return value from above method
    {   
        $result = (array)json_decode($this->bitcoindConn->getblock($blockHash));
        $this->assertEquals($result['error'], $blockHash);
    }
}

So if you need to save more state between tests, return more data in that method. I would guess that the reason PHPUnit makes this annoying is to discourage dependent tests.

See the official documentation for details.

Upvotes: 59

quazardous
quazardous

Reputation: 876

You can use a static variable within a function... PHP annoyingly shares static variables of class methods with all the instances... But in this cas it can help :p

protected function &getSharedVar()
{
    static $value = null;
    return $value;
}

...

public function testTest1()
{
    $value = &$this->getSharedVar();

    $value = 'Hello Test 2';
}


public function testTest2()
{
    $value = &$this->getSharedVar();

    // $value should be ok
}

NB: this is NOT the good way but it helps if you need some data in all your tests...

Upvotes: 10

Related Questions