2

Is it possible to access $this in a PHPUnit BrowserTestBase data provider method to get access to properties defined in the testBase class? It seems that the sequence of processing during startup of the tests means that the properties in my test base class are not available at the dataProvider stage, they are only available after the test function has actually started, and received its first test data parameters. But by this time it is too late and NULL has already been passed as the value.

Example, my TestBase class has

  /**
   * @var string
   */
  protected $valueAsConstant = 'some predefined value';

  /**
   * @var string
   */
  protected $valueInSetup;

  /**
   * {@inheritdoc}
   */
  public function setUp() {
    parent::setUp();
    
    $this->valueInSetup = 'value given in setUp method';

  }

The actual test is

  /**
   * @dataProvider dataQuestion()
   */
  public function testQuestion($value) {
  }

  public function dataQuestion() {
    $data = [
      [$this->valueAsConstant],
      [$this->valueInSetup],
    ];
    return $data;
  }

This produces the following (url shortened for ease of reading)

Testing modules/d8testing
Test 'D8testingTest::testQuestion with data set #0 ('some predefined value')' started
Test 'D8testingTest::testQuestion with data set #0 ('some predefined value')' ended
Test 'D8testingTest::testQuestion with data set #1 (null)' started
Test 'D8testingTest::testQuestion with data set #1 (null)' ended
9
  • 1
    A data provider method isn't a static method, which means it can access $this as it does OffCanvasTestBase::themeDataProvider(). It would be better to show the code you are using, so the answers can better answer about what is wrong in your code.
    – apaderno
    Feb 10, 2021 at 12:04
  • Thanks @kiamlaluno. I see in the example you gave that themeDataProvider() exists in the OffCanvasTestBase class. The dataProvider function I am using is written in the actual test class. I will post my example here shortly, as I'm sure there is a simple way to solve it. Feb 10, 2021 at 13:08
  • I think I have discovered the reason why the properties are not available in the data provider. They are not defined directly in my TestBase class, but in the setUp() method of that TestBase class. There are two properties defined directly in the testBase, for example protected $defaultTheme = 'stark'; and this property is availbale in the data provider method. Other properties that are not populated until the setUp() method is called, remain as null Feb 10, 2021 at 14:05
  • Example of data provider public function dataNonEnabledType() { $data = [ 1 => [$this->typeName], 2 => [$this->mediaTypeName], 3 => [$this->defaultTheme], ]; return $data; } Feb 10, 2021 at 14:11
  • 1
    It would be better to put the code into the question. For what I recall, setUp() is called before the test are executed, which means before the data provider is called. The properties should be already set.
    – apaderno
    Feb 10, 2021 at 14:20

2 Answers 2

0

It seems not possible to use fields inside a dataprovider. A (temporary) workaround I used is to put an array in between:

public function setUp() {
  $this->fields = [
    'value_1' => $this->valueInSetup1,
    'value_2' => $this->valueInSetup2,
  ];
}
  /**
   * @dataProvider dataQuestion()
   */
  public function testQuestion($key) {
    $value = $this->fields[$key]
  }

  public function dataQuestion() {
    return [
      ['value_1'],
      ['value_2'],
    ];
  }

Which is not really a clean/readable approach though... So I will refactor this code later on so that accessing fields is not needed anymore inside the dataProvider, which is probably the best advice here.

0

I hit this problem today as well, and it seems you are correct in your assumption from the comments that properties initialized within setUp() are not available in the data provider. According to the documentation, the data provider is run before setUp(), which means that any properties that are initialized within setUp() won't be initialized in time to be used inside the data provider.

Lucky for me, I was only initializing two different instances of the same class inside my setUp(), and needed to use one or the other inside my different test cases. I therefore solved it in my case by creating two constants at the top of the test class, one for each object instance from setUp(). Then I put the corresponding constant inside the different test cases of the data provider, and used that data inside the test method to decide which of the class properties I needed for any given test case. Not elegant and scalable, but very straightforward and simple. YMMV.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.