448 lines
14 KiB
PHP
448 lines
14 KiB
PHP
|
|
<?php
|
||
|
|
use \Codeception\Util\Stub as Stub;
|
||
|
|
|
||
|
|
class StubTest extends \PHPUnit\Framework\TestCase
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* @var DummyClass
|
||
|
|
*/
|
||
|
|
protected $dummy;
|
||
|
|
|
||
|
|
public function setUp()
|
||
|
|
{
|
||
|
|
$conf = \Codeception\Configuration::config();
|
||
|
|
require_once $file = \Codeception\Configuration::dataDir().'DummyClass.php';
|
||
|
|
$this->dummy = new DummyClass(true);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmpty()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmpty('DummyClass');
|
||
|
|
$this->assertInstanceOf('DummyClass', $dummy);
|
||
|
|
$this->assertTrue(method_exists($dummy, 'helloWorld'));
|
||
|
|
$this->assertNull($dummy->helloWorld());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmptyMethodReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmpty('DummyClass', array('helloWorld' => function () {
|
||
|
|
return 'good bye world';
|
||
|
|
}));
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmptyMethodSimplyReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmpty('DummyClass', array('helloWorld' => 'good bye world'));
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmptyExcept()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmptyExcept('DummyClass', 'helloWorld');
|
||
|
|
$this->assertEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||
|
|
$this->assertNull($dummy->goodByeWorld());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmptyExceptPropertyReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMe', array('checkMe' => 'checked!'));
|
||
|
|
$this->assertEquals('checked!', $dummy->getCheckMe());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeEmptyExceptMagicalPropertyReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMeToo', array('checkMeToo' => 'checked!'));
|
||
|
|
$this->assertEquals('checked!', $dummy->getCheckMeToo());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testFactory()
|
||
|
|
{
|
||
|
|
$dummies = Stub::factory('DummyClass', 2);
|
||
|
|
$this->assertCount(2, $dummies);
|
||
|
|
$this->assertInstanceOf('DummyClass', $dummies[0]);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMake()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('goodByeWorld' => function () {
|
||
|
|
return 'hello world';
|
||
|
|
}));
|
||
|
|
$this->assertEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||
|
|
$this->assertEquals("hello world", $dummy->goodByeWorld());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeMethodReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('helloWorld' => function () {
|
||
|
|
return 'good bye world';
|
||
|
|
}));
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeWithMagicalPropertiesReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('checkMeToo' => 'checked!'));
|
||
|
|
$this->assertEquals('checked!', $dummy->checkMeToo);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testMakeMethodSimplyReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('helloWorld' => 'good bye world'));
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testCopy()
|
||
|
|
{
|
||
|
|
$dummy = Stub::copy($this->dummy, array('checkMe' => 'checked!'));
|
||
|
|
$this->assertEquals('checked!', $dummy->getCheckMe());
|
||
|
|
$dummy = Stub::copy($this->dummy, array('checkMeToo' => 'checked!'));
|
||
|
|
$this->assertEquals('checked!', $dummy->getCheckMeToo());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConstruct()
|
||
|
|
{
|
||
|
|
$dummy = Stub::construct('DummyClass', array('checkMe' => 'checked!'));
|
||
|
|
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||
|
|
|
||
|
|
$dummy = Stub::construct(
|
||
|
|
'DummyClass',
|
||
|
|
array('checkMe' => 'checked!'),
|
||
|
|
array('targetMethod' => function () {
|
||
|
|
return false;
|
||
|
|
})
|
||
|
|
);
|
||
|
|
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||
|
|
$this->assertEquals(false, $dummy->targetMethod());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConstructMethodReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::construct(
|
||
|
|
'DummyClass',
|
||
|
|
array(),
|
||
|
|
array('helloWorld' => function () {
|
||
|
|
return 'good bye world';
|
||
|
|
})
|
||
|
|
);
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConstructMethodSimplyReplaced()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('helloWorld' => 'good bye world'));
|
||
|
|
$this->assertMethodReplaced($dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConstructEmpty()
|
||
|
|
{
|
||
|
|
$dummy = Stub::constructEmpty('DummyClass', array('checkMe' => 'checked!'));
|
||
|
|
$this->assertNull($dummy->getCheckMe());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConstructEmptyExcept()
|
||
|
|
{
|
||
|
|
$dummy = Stub::constructEmptyExcept('DummyClass', 'getCheckMe', array('checkMe' => 'checked!'));
|
||
|
|
$this->assertNull($dummy->targetMethod());
|
||
|
|
$this->assertEquals('constructed: checked!', $dummy->getCheckMe());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testUpdate()
|
||
|
|
{
|
||
|
|
$dummy = Stub::construct('DummyClass');
|
||
|
|
Stub::update($dummy, array('checkMe' => 'done'));
|
||
|
|
$this->assertEquals('done', $dummy->getCheckMe());
|
||
|
|
Stub::update($dummy, array('checkMeToo' => 'done'));
|
||
|
|
$this->assertEquals('done', $dummy->getCheckMeToo());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testStubsFromObject()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make(new \DummyClass());
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::make(new \DummyOverloadableClass());
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
$dummy = Stub::makeEmpty(new \DummyClass());
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::makeEmpty(new \DummyOverloadableClass());
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
$dummy = Stub::makeEmptyExcept(new \DummyClass(), 'helloWorld');
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::makeEmptyExcept(new \DummyOverloadableClass(), 'helloWorld');
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
$dummy = Stub::construct(new \DummyClass());
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::construct(new \DummyOverloadableClass());
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
$dummy = Stub::constructEmpty(new \DummyClass());
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::constructEmpty(new \DummyOverloadableClass());
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
$dummy = Stub::constructEmptyExcept(new \DummyClass(), 'helloWorld');
|
||
|
|
$this->assertInstanceOf(
|
||
|
|
'\PHPUnit_Framework_MockObject_MockObject',
|
||
|
|
$dummy
|
||
|
|
);
|
||
|
|
$dummy = Stub::constructEmptyExcept(new \DummyOverloadableClass(), 'helloWorld');
|
||
|
|
$this->assertObjectHasAttribute('__mocked', $dummy);
|
||
|
|
}
|
||
|
|
|
||
|
|
protected function assertMethodReplaced($dummy)
|
||
|
|
{
|
||
|
|
$this->assertTrue(method_exists($dummy, 'helloWorld'));
|
||
|
|
$this->assertNotEquals($this->dummy->helloWorld(), $dummy->helloWorld());
|
||
|
|
$this->assertEquals($dummy->helloWorld(), 'good bye world');
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function matcherAndFailMessageProvider()
|
||
|
|
{
|
||
|
|
return array(
|
||
|
|
array(Stub::never(),
|
||
|
|
"DummyClass::targetMethod() was not expected to be called."
|
||
|
|
),
|
||
|
|
array(Stub::atLeastOnce(),
|
||
|
|
"Expectation failed for method name is equal to <string:targetMethod> when invoked at least once.\n"
|
||
|
|
. 'Expected invocation at least once but it never occured.'
|
||
|
|
),
|
||
|
|
array(Stub::once(),
|
||
|
|
"Expectation failed for method name is equal to <string:targetMethod> when invoked 1 time(s).\n"
|
||
|
|
. 'Method was expected to be called 1 times, actually called 0 times.'
|
||
|
|
),
|
||
|
|
array(Stub::exactly(1),
|
||
|
|
"Expectation failed for method name is equal to <string:targetMethod> when invoked 3 time(s).\n"
|
||
|
|
. 'Method was expected to be called 3 times, actually called 0 times.'
|
||
|
|
),
|
||
|
|
array(Stub::exactly(3),
|
||
|
|
"Expectation failed for method name is equal to <string:targetMethod> when invoked 3 time(s).\n"
|
||
|
|
. 'Method was expected to be called 3 times, actually called 0 times.'
|
||
|
|
),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherAndFailMessageProvider
|
||
|
|
*/
|
||
|
|
public function testMockedMethodIsCalledFail($stubMarshaler, $failMessage)
|
||
|
|
{
|
||
|
|
$mock = Stub::makeEmptyExcept('DummyClass', 'call', array('targetMethod' => $stubMarshaler), $this);
|
||
|
|
$mock->goodByeWorld();
|
||
|
|
|
||
|
|
try {
|
||
|
|
if ($this->thereAreNeverMatcher($stubMarshaler)) {
|
||
|
|
$this->thenWeMustCallMethodForException($mock);
|
||
|
|
} else {
|
||
|
|
$this->thenWeDontCallAnyMethodForExceptionJustVerify($mock);
|
||
|
|
}
|
||
|
|
} catch (PHPUnit\Framework\ExpectationFailedException $e) {
|
||
|
|
$this->assertSame($failMessage, $e->getMessage());
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->resetMockObjects();
|
||
|
|
}
|
||
|
|
|
||
|
|
private function thenWeMustCallMethodForException($mock)
|
||
|
|
{
|
||
|
|
$mock->call();
|
||
|
|
}
|
||
|
|
|
||
|
|
private function thenWeDontCallAnyMethodForExceptionJustVerify($mock)
|
||
|
|
{
|
||
|
|
$mock->__phpunit_verify();
|
||
|
|
$this->fail('Expected exception');
|
||
|
|
}
|
||
|
|
|
||
|
|
private function thereAreNeverMatcher($stubMarshaler)
|
||
|
|
{
|
||
|
|
$matcher = $stubMarshaler->getMatcher();
|
||
|
|
|
||
|
|
return 0 == $matcher->getInvocationCount();
|
||
|
|
}
|
||
|
|
|
||
|
|
private function resetMockObjects()
|
||
|
|
{
|
||
|
|
$refl = new ReflectionObject($this);
|
||
|
|
$refl = $refl->getParentClass();
|
||
|
|
$prop = $refl->getProperty('mockObjects');
|
||
|
|
$prop->setAccessible(true);
|
||
|
|
$prop->setValue($this, array());
|
||
|
|
}
|
||
|
|
|
||
|
|
public static function matcherProvider()
|
||
|
|
{
|
||
|
|
return array(
|
||
|
|
array(0, Stub::never()),
|
||
|
|
array(1, Stub::once()),
|
||
|
|
array(2, Stub::atLeastOnce()),
|
||
|
|
array(3, Stub::exactly(3)),
|
||
|
|
array(1, Stub::once(function () {
|
||
|
|
return true;
|
||
|
|
}), true),
|
||
|
|
array(2, Stub::atLeastOnce(function () {
|
||
|
|
return array();
|
||
|
|
}), array()),
|
||
|
|
array(1, Stub::exactly(1, function () {
|
||
|
|
return null;
|
||
|
|
}), null),
|
||
|
|
array(1, Stub::exactly(1, function () {
|
||
|
|
return 'hello world!';
|
||
|
|
}), 'hello world!'),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithMake($count, $matcher, $expected = false)
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('goodByeWorld' => $matcher), $this);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'), $expected);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithMakeEmpty($count, $matcher)
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmpty('DummyClass', array('goodByeWorld' => $matcher), $this);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithMakeEmptyExcept($count, $matcher)
|
||
|
|
{
|
||
|
|
$dummy = Stub::makeEmptyExcept('DummyClass', 'getCheckMe', array('goodByeWorld' => $matcher), $this);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithConstruct($count, $matcher)
|
||
|
|
{
|
||
|
|
$dummy = Stub::construct('DummyClass', array(), array('goodByeWorld' => $matcher), $this);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithConstructEmpty($count, $matcher)
|
||
|
|
{
|
||
|
|
$dummy = Stub::constructEmpty('DummyClass', array(), array('goodByeWorld' => $matcher), $this);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @dataProvider matcherProvider
|
||
|
|
*/
|
||
|
|
public function testMethodMatcherWithConstructEmptyExcept($count, $matcher)
|
||
|
|
{
|
||
|
|
$dummy = Stub::constructEmptyExcept(
|
||
|
|
'DummyClass',
|
||
|
|
'getCheckMe',
|
||
|
|
array(),
|
||
|
|
array('goodByeWorld' => $matcher),
|
||
|
|
$this
|
||
|
|
);
|
||
|
|
|
||
|
|
$this->repeatCall($count, array($dummy, 'goodByeWorld'));
|
||
|
|
}
|
||
|
|
|
||
|
|
private function repeatCall($count, $callable, $expected = false)
|
||
|
|
{
|
||
|
|
for ($i = 0; $i < $count; $i++) {
|
||
|
|
$actual = call_user_func($callable);
|
||
|
|
if ($expected) {
|
||
|
|
$this->assertEquals($expected, $actual);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testConsecutive()
|
||
|
|
{
|
||
|
|
$dummy = Stub::make('DummyClass', array('helloWorld' => Stub::consecutive('david', 'emma', 'sam', 'amy')));
|
||
|
|
|
||
|
|
$this->assertEquals('david', $dummy->helloWorld());
|
||
|
|
$this->assertEquals('emma', $dummy->helloWorld());
|
||
|
|
$this->assertEquals('sam', $dummy->helloWorld());
|
||
|
|
$this->assertEquals('amy', $dummy->helloWorld());
|
||
|
|
|
||
|
|
// Expected null value when no more values
|
||
|
|
$this->assertNull($dummy->helloWorld());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testStubPrivateProperties()
|
||
|
|
{
|
||
|
|
$tester = Stub::construct(
|
||
|
|
'MyClassWithPrivateProperties',
|
||
|
|
['name' => 'gamma'],
|
||
|
|
[
|
||
|
|
'randomName' => 'chicken',
|
||
|
|
't' => 'ticky2',
|
||
|
|
'getRandomName' => function () {
|
||
|
|
return "randomstuff";
|
||
|
|
}
|
||
|
|
]
|
||
|
|
);
|
||
|
|
$this->assertEquals('gamma', $tester->getName());
|
||
|
|
$this->assertEquals('randomstuff', $tester->getRandomName());
|
||
|
|
$this->assertEquals('ticky2', $tester->getT());
|
||
|
|
}
|
||
|
|
|
||
|
|
public function testStubMakeEmptyInterface()
|
||
|
|
{
|
||
|
|
$stub = Stub::makeEmpty('\Countable', ['count' => 5]);
|
||
|
|
$this->assertEquals(5, $stub->count());
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
class MyClassWithPrivateProperties
|
||
|
|
{
|
||
|
|
|
||
|
|
private $name;
|
||
|
|
private $randomName = "gaia";
|
||
|
|
private $t = "ticky";
|
||
|
|
|
||
|
|
public function __construct($name)
|
||
|
|
{
|
||
|
|
$this->name = $name;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getName()
|
||
|
|
{
|
||
|
|
return $this->name;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getRandomName()
|
||
|
|
{
|
||
|
|
return $this->randomName;
|
||
|
|
}
|
||
|
|
|
||
|
|
public function getT()
|
||
|
|
{
|
||
|
|
return $this->t;
|
||
|
|
}
|
||
|
|
}
|