Compare commits

..

No commits in common. "main" and "1.1.0.0" have entirely different histories.

8 changed files with 66 additions and 102 deletions

View File

@ -18,7 +18,6 @@ namespace D3\TestingTools\Tests\Unit\Development;
use D3\TestingTools\Development\CanAccessRestricted; use D3\TestingTools\Development\CanAccessRestricted;
use D3\TestingTools\Tests\Unit\Development\HelperClasses\CanAccessRestrictedClass; use D3\TestingTools\Tests\Unit\Development\HelperClasses\CanAccessRestrictedClass;
use Error; use Error;
use Generator;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use ReflectionException; use ReflectionException;
@ -27,7 +26,7 @@ class CanAccessRestrictedTest extends TestCase
use CanAccessRestricted; use CanAccessRestricted;
/** @var CanAccessRestrictedClass */ /** @var CanAccessRestrictedClass */
public CanAccessRestrictedClass $class; public $class;
public function setUp(): void public function setUp(): void
{ {
@ -82,12 +81,17 @@ class CanAccessRestrictedTest extends TestCase
); );
} }
public function canCallMethodDataProvider(): Generator /**
* @return array
*/
public function canCallMethodDataProvider(): array
{ {
yield 'public method' => ['publicMethod', true]; return [
yield 'protected method' => ['protectedMethod', false]; 'public method' => ['publicMethod', true],
yield 'private method' => ['privateMethod', false]; 'protected method' => ['protectedMethod', false],
yield 'final public method' => ['finalPublicMethod', true]; 'private method' => ['privateMethod', false],
'final public method' => ['finalPublicMethod', true],
];
} }
/** /**
@ -141,11 +145,16 @@ class CanAccessRestrictedTest extends TestCase
); );
} }
public function canSetAndGetClassPropertiesDataProvider(): Generator /**
* @return array
*/
public function canSetAndGetClassPropertiesDataProvider(): array
{ {
yield 'public property' => ['publicProperty', true]; return [
yield 'protected property' => ['protectedProperty', false]; 'public property' => ['publicProperty', true],
yield 'private property' => ['privateProperty', false]; 'protected property' => ['protectedProperty', false],
'private property' => ['privateProperty', false],
];
} }
/** /**
@ -207,11 +216,16 @@ class CanAccessRestrictedTest extends TestCase
); );
} }
public function canSetAndGetMockedPropertiesDataProvider(): Generator /**
* @return array
*/
public function canSetAndGetMockedPropertiesDataProvider(): array
{ {
yield 'public property' => ['publicProperty', true]; return [
yield 'protected property' => ['protectedProperty', false]; 'public property' => ['publicProperty', true],
yield 'private property' => ['privateProperty', true]; // because private properties not contained in mock 'protected property' => ['protectedProperty', false],
'private property' => ['privateProperty', true], // because private properties not contained in mock
];
} }
/** /**

View File

@ -18,13 +18,13 @@ namespace D3\TestingTools\Tests\Unit\Development\HelperClasses;
class CanAccessRestrictedClass class CanAccessRestrictedClass
{ {
/** @var string */ /** @var string */
public string $publicProperty = 'publicProperty'; public $publicProperty = 'publicProperty';
/** @var string */ /** @var string */
protected string $protectedProperty = 'protectedProperty'; protected $protectedProperty = 'protectedProperty';
/** @var string */ /** @var string */
private string $privateProperty = 'privateProperty'; private $privateProperty = 'privateProperty';
/** /**
* @param string $arg * @param string $arg

View File

@ -28,10 +28,6 @@ class IsMockableClass extends IsMockableParent
*/ */
public function myMethod(string $arg): string public function myMethod(string $arg): string
{ {
return 'currentClass::myMethod##'.$arg; return 'currentClass::myMethod##.'.$arg;
}
public function fakeMethod(): void
{
} }
} }

View File

@ -18,12 +18,10 @@ namespace D3\TestingTools\Tests\Unit\Production;
use D3\TestingTools\Development\CanAccessRestricted; use D3\TestingTools\Development\CanAccessRestricted;
use D3\TestingTools\Production\IsMockable; use D3\TestingTools\Production\IsMockable;
use D3\TestingTools\Tests\Unit\Production\HelperClasses\IsMockableClass; use D3\TestingTools\Tests\Unit\Production\HelperClasses\IsMockableClass;
use D3\TestingTools\Tests\Unit\Production\HelperClasses\IsMockableParent;
use Generator;
use OxidEsales\Eshop\Application\Model\Article;
use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
use ReflectionException; use ReflectionException;
use RuntimeException;
class IsMockableTest extends TestCase class IsMockableTest extends TestCase
{ {
@ -32,80 +30,44 @@ class IsMockableTest extends TestCase
/** /**
* @test * @test
* @throws ReflectionException * @throws ReflectionException
* @covers \D3\TestingTools\Production\IsMockable::d3CallMockableFunction
*/ */
public function callMockableFunctionMissingFunction(): void public function callMockableNoParent(): void
{ {
$methodName = $this->getRandomString(); $methodName = $this->getRandomString();
$argument = $this->getRandomString(); $argument = $this->getRandomString();
$traitMock = $this->getObjectForTrait(IsMockable::class); $traitMock = $this->getObjectForTrait(IsMockable::class);
// argument #1 is not a valid callable $this->expectException(RuntimeException::class);
$this->expectError();
$this->callMethod( $this->callMethod(
$traitMock, $traitMock,
'd3CallMockableFunction', 'd3CallMockableParent',
[[$traitMock, $methodName], [$argument]] [$methodName, [$argument]]
); );
} }
/** /**
* @param string $fqClassName
* @param string $expected
*
* @throws ReflectionException
* @test * @test
* @dataProvider callMockableFunctionFromClassDataProvider * @throws ReflectionException
* @covers \D3\TestingTools\Production\IsMockable::d3CallMockableFunction
*/ */
public function callMockableFunctionFromClass(string $fqClassName, string $expected): void public function callMockableParent(): void
{ {
$methodName = 'myMethod'; $methodName = 'myMethod';
$argument = $this->getRandomString(); $argument = $this->getRandomString();
/** @var MockObject $mock */ /** @var MockObject $mock */
$mock = new(IsMockableClass::class); $mock = $this->getMockBuilder(IsMockableClass::class)
->getMock();
if ($fqClassName === 'mockObject') { // method from mocked class will never call, run method from parent class only
$fqClassName = $mock; $mock->expects($this->never())->method($methodName);
}
$this->assertSame( $this->assertSame(
$expected.$argument, 'ParentClass::myMethod##'.$argument,
$this->callMethod( $this->callMethod(
$mock, $mock,
'd3CallMockableFunction', 'd3CallMockableParent',
[[$fqClassName, $methodName], [$argument]] [$methodName, [$argument]]
)
);
}
public function callMockableFunctionFromClassDataProvider(): Generator
{
yield 'parent static method' => [IsMockableParent::class, 'ParentClass::myMethod##'];
yield 'current static method' => [IsMockableClass::class, 'currentClass::myMethod##'];
yield 'current object method' => ['mockObject', 'currentClass::myMethod##'];
}
/**
* @test
* @return void
* @throws ReflectionException
* @covers \D3\TestingTools\Production\IsMockable::d3GetMockableOxNewObject
*/
public function canGetMockableOxNewObject()
{
/** @var MockObject $mock */
$mock = new(IsMockableClass::class);
$this->assertInstanceOf(
Article::class,
$this->callMethod(
$mock,
'd3GetMockableOxNewObject',
[Article::class]
) )
); );
} }

View File

@ -25,7 +25,7 @@
"MIT" "MIT"
], ],
"require": { "require": {
"php": "^8" "php": "^7.1 || ^8"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit" : "^9.5", "phpunit/phpunit" : "^9.5",
@ -39,9 +39,8 @@
} }
}, },
"scripts": { "scripts": {
"runtests": "XDEBUG_MODE=coverage ./vendor/bin/phpunit --bootstrap=source/bootstrap.php --config=vendor/d3/testingtools/", "runtests": "./vendor/bin/phpunit",
"php-cs-fixer_audit": "./vendor/bin/php-cs-fixer list-files --config=./vendor/d3/testingtools/.php-cs-fixer.php", "csfixer": "./vendor/bin/php-cs-fixer fix",
"php-cs-fixer_fix": "./vendor/bin/php-cs-fixer fix --config=./vendor/d3/testingtools/.php-cs-fixer.php", "phpstan": "./vendor/bin/phpstan analyse src Tests"
"phpstan": "./vendor/bin/phpstan analyse -c./vendor/d3/testingtools/phpstan.neon"
} }
} }

View File

@ -1,12 +1,6 @@
parameters: parameters:
scanFiles:
- ../../oxid-esales/oxideshop-ce/source/bootstrap.php
- ../../oxid-esales/oxideshop-ce/source/oxfunctions.php
- ../../oxid-esales/oxideshop-ce/source/overridablefunctions.php
paths:
- .
level: 9 level: 9
phpVersion: 80000 phpVersion: 70100
checkMissingIterableValueType: false checkMissingIterableValueType: false
ignoreErrors: ignoreErrors:
- '#Property D3\\TestingTools\\Tests\\Unit\\Development\\HelperClasses\\CanAccessRestrictedClass::\$privateProperty is never read, only written.#' - '#Property D3\\TestingTools\\Tests\\Unit\\Development\\HelperClasses\\CanAccessRestrictedClass::\$privateProperty is never read, only written.#'

View File

@ -23,33 +23,32 @@ use ReflectionProperty;
trait CanAccessRestricted trait CanAccessRestricted
{ {
/** /**
* Calls a public, private or protected object method. * Calls a private or protected object method.
* *
* @param object $object * @param object $object
* @param string $methodName * @param string $methodName
* @param array $arguments * @param array $arguments
* *
* @return mixed * @return mixed
* @throws ReflectionException * @throws ReflectionException
*/ */
public function callMethod(object $object, string $methodName, array $arguments = []): mixed public function callMethod($object, string $methodName, array $arguments = [])
{ {
$class = new ReflectionClass($object); $class = new ReflectionClass($object);
$method = $class->getMethod($methodName); $method = $class->getMethod($methodName);
$method->setAccessible(true); $method->setAccessible(true);
return $method->invokeArgs($object, $arguments); return $method->invokeArgs($object, $arguments);
} }
/** /**
* Sets a public, private or protected property in class instance * Sets a private or protected property in defined class instance
* *
* @param object $object * @param object $object
* @param string $valueName * @param string $valueName
* @param mixed $value * @param mixed $value
* @throws ReflectionException * @throws ReflectionException
*/ */
public function setValue(object $object, string $valueName, mixed $value): void public function setValue($object, string $valueName, $value): void
{ {
$reflection = new ReflectionClass($object); $reflection = new ReflectionClass($object);
$property = $reflection->getProperty($valueName); $property = $reflection->getProperty($valueName);
@ -58,14 +57,14 @@ trait CanAccessRestricted
} }
/** /**
* get a public, private or protected property from class instance * get a private or protected property from defined class instance
* *
* @param object $object * @param object $object
* @param string $valueName * @param string $valueName
* @return mixed * @return mixed
* @throws ReflectionException * @throws ReflectionException
*/ */
public function getValue(object $object, string $valueName): mixed public function getValue($object, string $valueName)
{ {
$reflection = new ReflectionClass($object); $reflection = new ReflectionClass($object);
$property = $reflection->getProperty($valueName); $property = $reflection->getProperty($valueName);
@ -74,7 +73,7 @@ trait CanAccessRestricted
} }
/** /**
* Sets a public, private or protected property in mocked class instance based on original class * Sets a private or protected property in mocked class instance based on original class
* (required for e.g. final properties, which aren't contained in mock, but in original class) * (required for e.g. final properties, which aren't contained in mock, but in original class)
* @param string $mockedClassName * FQNS of original class * @param string $mockedClassName * FQNS of original class
* @param MockObject $object * mock object * @param MockObject $object * mock object
@ -83,7 +82,7 @@ trait CanAccessRestricted
* *
* @throws ReflectionException * @throws ReflectionException
*/ */
public function setMockedClassValue(string $mockedClassName, MockObject $object, string $valueName, mixed $value): void public function setMockedClassValue(string $mockedClassName, MockObject $object, string $valueName, $value): void
{ {
$property = new ReflectionProperty($mockedClassName, $valueName); $property = new ReflectionProperty($mockedClassName, $valueName);
$property->setAccessible(true); $property->setAccessible(true);
@ -101,7 +100,7 @@ trait CanAccessRestricted
* @return mixed * @return mixed
* @throws ReflectionException * @throws ReflectionException
*/ */
public function getMockedClassValue(string $mockedClassName, MockObject $object, string $valueName): mixed public function getMockedClassValue(string $mockedClassName, MockObject $object, string $valueName)
{ {
$property = new ReflectionProperty($mockedClassName, $valueName); $property = new ReflectionProperty($mockedClassName, $valueName);
$property->setAccessible(true); $property->setAccessible(true);

View File

@ -23,12 +23,12 @@ trait IsMockable
/** /**
* mockable wrapper for uncertain parent calls * mockable wrapper for uncertain parent calls
* *
* @param callable $callable * @param string $methodName
* @param array $arguments * @param array $arguments
* *
* @return false|mixed * @return false|mixed
*/ */
protected function d3CallMockableFunction(callable $callable, array $arguments = []): mixed protected function d3CallMockableFunction(callable $callable, array $arguments = [])
{ {
return call_user_func_array($callable, $arguments); return call_user_func_array($callable, $arguments);
} }
@ -54,7 +54,7 @@ trait IsMockable
* *
* @return T * @return T
*/ */
protected function d3GetMockableOxNewObject(string $className, mixed ...$args) protected function d3GetMockableOxNewObject(string $className)
{ {
$arguments = func_get_args(); $arguments = func_get_args();
return call_user_func_array("oxNew", $arguments); return call_user_func_array("oxNew", $arguments);