te')); return $arr; } /* 遍历用户所有主题 * @param $uid 用户ID * @param int $page 页数 * @param int $pagesize 每页记录条数 * @param bool $desc 排序方式 TRUE降序 FALSE升序 * @param string $key 返回的数组用那一列的值作为 key * @param array $col 查询哪些列 */ function thread_tid_find_by_uid($uid, $page = 1, $pagesize = 1000, $desc = TRUE, $key = 'tid', $col = array()) { if (empty($uid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('uid' => $uid), array('tid' => $orderby), $page, $pagesize, $key, $col); return $arr; } // 遍历栏目下tid 支持数组 $fid = array(1,2,3) function thread_tid_find_by_fid($fid, $page = 1, $pagesize = 1000, $desc = TRUE) { if (empty($fid)) return array(); $orderby = TRUE == $desc ? -1 : 1; $arr = thread_tid__find($cond = array('fid' => $fid), array('tid' => $orderby), $page, $pagesize, 'tid', array('tid', 'verify_date')); return $arr; } function thread_tid_delete($tid) { if (empty($tid)) return FALSE; $r = thread_tid__delete(array('tid' => $tid)); return $r; } function thread_tid_count() { $n = thread_tid__count(); return $n; } // 统计用户主题数 大数量下严谨使用非主键统计 function thread_uid_count($uid) { $n = thread_tid__count(array('uid' => $uid)); return $n; } // 统计栏目主题数 大数量下严谨使用非主键统计 function thread_fid_count($fid) { $n = thread_tid__count(array('fid' => $fid)); return $n; } ?>php - How to initialize member variable for phpunit test for them to be defined during dataProvider? - Stack Overflow
最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

php - How to initialize member variable for phpunit test for them to be defined during dataProvider? - Stack Overflow

programmeradmin2浏览0评论

I know I can use dataProvider like so:

use PHPUnit\Framework\TestCase;

class DataProviderSetupTest extends TestCase {
    /**
     * @dataProvider basicDataProvider
     */
    public function testDataProvider(string $expected): void
    {
        $actualResult = 'I am the value!'; // generated by some service under test
        $this->assertSame($expected, $actualResult);
    }

    public function basicDataProvider(): \Generator
    {
        yield 'no state, all fine' => ['I am the value!'];
    }
}

This test will run fine.

Yet if I have a property on the test class which is initialzied via setUp, it is null when the dataProvider is executed:

use PHPUnit\Framework\TestCase;

class DataProviderSetupTest extends TestCase
{
    protected string $state;

    protected function setUp(): void
    {
        $this->state = 'Thank you for the fish!';
    }

    /**
     * @dataProvider statefulDataProvider
     */

    public function testDataProviderWithStateDependency(string $expected): void
    {
        $actualResult = 'Thank you for the fish!'; // generated by some service under test
        $this->assertSame($expected, $actualResult);
    }

    public function statefulDataProvider(): \Generator
    {
        yield 'member not initialized' => [$this->state];
    }
}

This test will fail:

The data provider specified for DataProviderSetupTest::testDataProviderWithStateDependency is invalid.
Error: Typed property DataProviderSetupTest::$state must not be accessed before initialization

How to initialize test classes members so that I can use them within data providers?


I also tried setUpBeforeClass yet since that one is static, I cannot set member variables.


My phpunit version is 9.6.11.

I know I can use dataProvider like so:

use PHPUnit\Framework\TestCase;

class DataProviderSetupTest extends TestCase {
    /**
     * @dataProvider basicDataProvider
     */
    public function testDataProvider(string $expected): void
    {
        $actualResult = 'I am the value!'; // generated by some service under test
        $this->assertSame($expected, $actualResult);
    }

    public function basicDataProvider(): \Generator
    {
        yield 'no state, all fine' => ['I am the value!'];
    }
}

This test will run fine.

Yet if I have a property on the test class which is initialzied via setUp, it is null when the dataProvider is executed:

use PHPUnit\Framework\TestCase;

class DataProviderSetupTest extends TestCase
{
    protected string $state;

    protected function setUp(): void
    {
        $this->state = 'Thank you for the fish!';
    }

    /**
     * @dataProvider statefulDataProvider
     */

    public function testDataProviderWithStateDependency(string $expected): void
    {
        $actualResult = 'Thank you for the fish!'; // generated by some service under test
        $this->assertSame($expected, $actualResult);
    }

    public function statefulDataProvider(): \Generator
    {
        yield 'member not initialized' => [$this->state];
    }
}

This test will fail:

The data provider specified for DataProviderSetupTest::testDataProviderWithStateDependency is invalid.
Error: Typed property DataProviderSetupTest::$state must not be accessed before initialization

How to initialize test classes members so that I can use them within data providers?


I also tried setUpBeforeClass yet since that one is static, I cannot set member variables.


My phpunit version is 9.6.11.

Share Improve this question asked Feb 17 at 11:35 k0pernikusk0pernikus 66.7k77 gold badges242 silver badges361 bronze badges 2
  • Github issue on phpunit's project site – k0pernikus Commented Feb 17 at 12:08
  • Yes, data providers are static methods, and yes, there is setUpBeforeClass(). If you need a (data) "providing" function otherwise, make it private and call it in the objects' test-method as the object already exists then. – hakre Commented Feb 17 at 13:16
Add a comment  | 

2 Answers 2

Reset to default 1

This is not possible within phpunit, as they need the current behavior so they can compute the total number of tests.

See this closed phpunit issue for reference.


There is a proposed workaround by user machitgarha:

A solution would be defining a new private method and define as many variables as needed, as static ones inside it. Then, check if one of them is set, and if it is not, set all of them and return (or yield) them. This way, the variables will be declared only once, even if you have ten providers or whatever. Besides, you can use it in setUpBeforeClass() or setUp().

See it in an example:

private static function getData() {
    static $data, $anotherData;

    if (!isset($data)) {
        $data = new TestClass();
        $anotherData = [];
    }

    return [
        $data,
        // Or: clone $data
        $anotherData,
    ]; }

public static function setUpBeforeClass() {
    list(self::$sampleJson, self::$sampleData) = self::getData();  }

public function sampleProvider() {
    $data = self::getData();

    return [
        $data
    ]; }

DataProviders are called before Setup. I see two possibilities if the state variable is to be set dynamically. One has to store the values outside the test class.

  1. Use Zend_Registry. Of course, you can also write your own object (singleton) for storing values.
use PHPUnit\Framework\TestCase;

class DataProviderSetupTest extends TestCase
{
    protected function setUp(): void
    {
        \Zend_Registry::set('state', 'Thank you for the fish!');
    }

    /**
     * @dataProvider statefulDataProvider
     */
    public function testDataProviderWithStateDependency(\Zend_Registry $expected): void
    {
        $actual = 'Thank you for the fish!'; // generated by some service under test
        $this->assertSame($expected::get('state'), $actual);
    }

    public function statefulDataProvider(): \Generator
    {
        yield 'member not initialized' => [\Zend_Registry::getInstance()];
    }
}
  1. The dirty workaround is to use global variables. You have to consider whether you can live with it in tests. With an object, you can simply transport several variables.
use PHPUnit\Framework\TestCase;

$transportObject = new class {
    public string $state;
};

class DataProviderSetupTest extends TestCase
{
    protected function setUp(): void
    {
        global $transportObject;
        $transportObject->state = 'Thank you for the fish!';
    }

    /**
     * @dataProvider statefulDataProvider
     */
    public function testDataProviderWithStateDependency(object $expected): void
    {
        $actual = 'Thank you for the fish!'; // generated by some service under test
        $this->assertSame($expected->state, $actual);
    }

    public function statefulDataProvider(): \Generator
    {
        global $transportObject;
        yield 'member not initialized' => [$transportObject];
    }
}

与本文相关的文章

发布评论

评论列表(0)

  1. 暂无评论