Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mocking DB object can't use getDouble? #403

Closed
hrsetyono opened this issue Mar 8, 2023 · 1 comment
Closed

Mocking DB object can't use getDouble? #403

hrsetyono opened this issue Mar 8, 2023 · 1 comment

Comments

@hrsetyono
Copy link

hrsetyono commented Mar 8, 2023

Hi, I tried mocking the get() request for db object.

I followed this sample code and works fine:

// This works
$return = [
	0 => (object) ['id' => '1', 'name' => 'Book'],
	1 => (object) ['id' => '2', 'name' => 'CD'],
	2 => (object) ['id' => '3', 'name' => 'DVD'],
];
$db_result = $this->getMockBuilder('CI_DB_pdo_result')
	->disableOriginalConstructor()
	->getMock();
$db_result->method('result')->willReturn($return);
$db = $this->getMockBuilder('CI_DB_pdo_sqlite_driver')
	->disableOriginalConstructor()
	->getMock();
$db->method('get')->willReturn($db_result);
$this->obj->db = $db;

But it's quite wordy, so I tried to shorten it with getDouble():

$db_result = $this->getDouble('CI_DB_pdo_result', [
    'result' => $return,
]);
$db = $this->getDouble('CI_DB_pdo_sqlite_driver', [
    'get' => $db_result,
]);
$this->obj->db = $db;

But I got this error:

1) My_Model_test::test_data_is_valid
TypeError: Argument 1 passed to PHPUnit\Framework\MockObject\Builder\InvocationMocker::will() must implement interface PHPUnit\Framework\MockObject\Stub\Stub, instance of Mock_CI_DB_pdo_result_7a60da75 given, called in H:\my-project\vendor\kenjis\ci-phpunit-test\application\tests\_ci_phpunit_test\CIPHPUnitTestDouble.php on line 87

I wonder what's causing it since I correctly followed this guide to use the helper.

Thanks

EDIT

So I tested mocking something else with getDouble and get the same error. So it's not limited to db.

I tried changing the class to this but get the same error:

$db_result = $this->getDouble(CI_DB_pdo_result::class, [
    'result' => $return,
]);

I'm on PHP 7.4.30.

@hrsetyono
Copy link
Author

hrsetyono commented Mar 8, 2023

I fixed it by overriding getDouble at /application/tests/TestCase.php:

<?php

class TestCase extends CIPHPUnitTestCase {
  /**
   * Override to fix stub bug
   */
  public function getDouble($classname, $params, $constructor_params = false) {
    $mockBuilder = $this->getMockBuilder($classname);
    if ($constructor_params === false) {
      $mockBuilder->disableOriginalConstructor();
    }
    elseif (is_array($constructor_params)) {
      $mockBuilder->setConstructorArgs($constructor_params);
    }

    $methods = [];
    $onConsecutiveCalls = [];
    $otherCalls = [];

    foreach ($params as $key => $val) {
      if (is_int($key)) {
        $onConsecutiveCalls = array_merge($onConsecutiveCalls, $val);
        $methods[] = array_keys($val)[0];
      } else {
        $otherCalls[$key] = $val;
        $methods[] = $key;
      }
    }

    $mock = $mockBuilder->setMethods($methods)->getMock();

    foreach ($onConsecutiveCalls as $method => $returns) {
      $mock->expects($this->any())->method($method)
        ->will(
          call_user_func_array(
            [$this->testCase, 'onConsecutiveCalls'],
            $returns
          )
        );
    }

    foreach ($otherCalls as $method => $return) {
      if (is_object($return) && ($return instanceof PHPUnit_Framework_MockObject_Stub || $return instanceof PHPUnit\Framework\MockObject\Stub\Stub)) {
        $mock->expects($this->any())->method($method)
          ->will($return);
      }
      elseif (is_object($return) && $return instanceof Closure) {
        $mock->expects($this->any())->method($method)
          ->willReturnCallback($return);
      }
      elseif ($return === ':void') {
        $mock->expects($this->any())->method($method);
      }
      else {
        $mock->expects($this->any())->method($method)
          ->willReturn($return);
      }
    }

    return $mock;
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant