Skip to content
This repository was archived by the owner on Feb 20, 2023. It is now read-only.

Commit 73e7b07

Browse files
Implement stubbing and mocking of multiple interfaces using a single object
1 parent 7a45f2f commit 73e7b07

File tree

4 files changed

+139
-92
lines changed

4 files changed

+139
-92
lines changed

PHPUnit/Framework/MockObject/Generator.php

Lines changed: 106 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -150,25 +150,25 @@ class PHPUnit_Framework_MockObject_Generator
150150
/**
151151
* Returns a mock object for the specified class.
152152
*
153-
* @param string $originalClassName
154-
* @param array $methods
155-
* @param array $arguments
156-
* @param string $mockClassName
157-
* @param boolean $callOriginalConstructor
158-
* @param boolean $callOriginalClone
159-
* @param boolean $callAutoload
160-
* @param boolean $cloneArguments
161-
* @param boolean $callOriginalMethods
162-
* @param object $proxyTarget
153+
* @param array|string $type
154+
* @param array $methods
155+
* @param array $arguments
156+
* @param string $mockClassName
157+
* @param boolean $callOriginalConstructor
158+
* @param boolean $callOriginalClone
159+
* @param boolean $callAutoload
160+
* @param boolean $cloneArguments
161+
* @param boolean $callOriginalMethods
162+
* @param object $proxyTarget
163163
* @return object
164164
* @throws InvalidArgumentException
165165
* @throws PHPUnit_Framework_Exception
166166
* @since Method available since Release 1.0.0
167167
*/
168-
public function getMock($originalClassName, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = TRUE, $callOriginalMethods = FALSE, $proxyTarget = NULL)
168+
public function getMock($type, $methods = array(), array $arguments = array(), $mockClassName = '', $callOriginalConstructor = TRUE, $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = TRUE, $callOriginalMethods = FALSE, $proxyTarget = NULL)
169169
{
170-
if (!is_string($originalClassName)) {
171-
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'string');
170+
if (!is_array($type) && !is_string($type)) {
171+
throw PHPUnit_Util_InvalidArgumentHelper::factory(1, 'array or string');
172172
}
173173

174174
if (!is_string($mockClassName)) {
@@ -215,7 +215,7 @@ public function getMock($originalClassName, $methods = array(), array $arguments
215215
}
216216

217217
$mock = $this->generate(
218-
$originalClassName,
218+
$type,
219219
$methods,
220220
$mockClassName,
221221
$callOriginalClone,
@@ -227,7 +227,7 @@ public function getMock($originalClassName, $methods = array(), array $arguments
227227
return $this->getObject(
228228
$mock['code'],
229229
$mock['mockClassName'],
230-
$originalClassName,
230+
$type,
231231
$callOriginalConstructor,
232232
$callAutoload,
233233
$arguments,
@@ -237,22 +237,23 @@ public function getMock($originalClassName, $methods = array(), array $arguments
237237
}
238238

239239
/**
240-
* @param string $code
241-
* @param string $className
242-
* @param string $originalClassName
243-
* @param boolean $callOriginalConstructor
244-
* @param boolean $callAutoload
245-
* @param array $arguments
246-
* @param boolean $callOriginalMethods
247-
* @param object $proxyTarget
240+
* @param string $code
241+
* @param string $className
242+
* @param array|string $type
243+
* @param boolean $callOriginalConstructor
244+
* @param boolean $callAutoload
245+
* @param array $arguments
246+
* @param boolean $callOriginalMethods
247+
* @param object $proxyTarget
248248
* @return object
249249
*/
250-
protected function getObject($code, $className, $originalClassName = '', $callOriginalConstructor = FALSE, $callAutoload = FALSE, array $arguments = array(), $callOriginalMethods = FALSE, $proxyTarget = NULL)
250+
protected function getObject($code, $className, $type = '', $callOriginalConstructor = FALSE, $callAutoload = FALSE, array $arguments = array(), $callOriginalMethods = FALSE, $proxyTarget = NULL)
251251
{
252252
$this->evalClass($code, $className);
253253

254254
if ($callOriginalConstructor &&
255-
!interface_exists($originalClassName, $callAutoload)) {
255+
is_string($type) &&
256+
!interface_exists($type, $callAutoload)) {
256257
if (count($arguments) == 0) {
257258
$object = new $className;
258259
} else {
@@ -267,9 +268,9 @@ protected function getObject($code, $className, $originalClassName = '', $callOr
267268
if ($callOriginalMethods) {
268269
if (!is_object($proxyTarget)) {
269270
if (count($arguments) == 0) {
270-
$proxyTarget = new $originalClassName;
271+
$proxyTarget = new $type;
271272
} else {
272-
$class = new ReflectionClass($originalClassName);
273+
$class = new ReflectionClass($type);
273274
$proxyTarget = $class->newInstanceArgs($arguments);
274275
}
275276
}
@@ -346,10 +347,7 @@ interface_exists($originalClassName, $callAutoload)) {
346347
);
347348
} else {
348349
throw new PHPUnit_Framework_Exception(
349-
sprintf(
350-
'Class "%s" does not exist.',
351-
$originalClassName
352-
)
350+
sprintf('Class "%s" does not exist.', $originalClassName)
353351
);
354352
}
355353
}
@@ -474,20 +472,24 @@ public function getObjectForTrait($traitName, array $arguments = array(), $trait
474472
}
475473

476474
/**
477-
* @param string $originalClassName
478-
* @param array $methods
479-
* @param string $mockClassName
480-
* @param boolean $callOriginalClone
481-
* @param boolean $callAutoload
482-
* @param boolean $cloneArguments
483-
* @param boolean $callOriginalMethods
475+
* @param array|string $type
476+
* @param array $methods
477+
* @param string $mockClassName
478+
* @param boolean $callOriginalClone
479+
* @param boolean $callAutoload
480+
* @param boolean $cloneArguments
481+
* @param boolean $callOriginalMethods
484482
* @return array
485483
*/
486-
public function generate($originalClassName, array $methods = NULL, $mockClassName = '', $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = TRUE, $callOriginalMethods = FALSE)
484+
public function generate($type, array $methods = NULL, $mockClassName = '', $callOriginalClone = TRUE, $callAutoload = TRUE, $cloneArguments = TRUE, $callOriginalMethods = FALSE)
487485
{
486+
if (is_array($type)) {
487+
sort($type);
488+
}
489+
488490
if ($mockClassName == '') {
489491
$key = md5(
490-
$originalClassName .
492+
is_array($type) ? join('_', $type) : $type .
491493
serialize($methods) .
492494
serialize($callOriginalClone) .
493495
serialize($cloneArguments) .
@@ -500,7 +502,7 @@ public function generate($originalClassName, array $methods = NULL, $mockClassNa
500502
}
501503

502504
$mock = $this->generateMock(
503-
$originalClassName,
505+
$type,
504506
$methods,
505507
$mockClassName,
506508
$callOriginalClone,
@@ -518,13 +520,13 @@ public function generate($originalClassName, array $methods = NULL, $mockClassNa
518520

519521
/**
520522
* @param string $wsdlFile
521-
* @param string $originalClassName
523+
* @param string $className
522524
* @param array $methods
523525
* @param array $options
524526
* @return string
525527
* @throws PHPUnit_Framework_Exception
526528
*/
527-
public function generateClassFromWsdl($wsdlFile, $originalClassName, array $methods = array(), array $options = array())
529+
public function generateClassFromWsdl($wsdlFile, $className, array $methods = array(), array $options = array())
528530
{
529531
if ($this->soapLoaded === NULL) {
530532
$this->soapLoaded = extension_loaded('soap');
@@ -588,16 +590,16 @@ public function generateClassFromWsdl($wsdlFile, $originalClassName, array $meth
588590

589591
$namespace = '';
590592

591-
if (strpos($originalClassName, '\\') !== FALSE) {
592-
$parts = explode('\\', $originalClassName);
593-
$originalClassName = array_pop($parts);
594-
$namespace = 'namespace ' . join('\\', $parts) . ';';
593+
if (strpos($className, '\\') !== FALSE) {
594+
$parts = explode('\\', $className);
595+
$className = array_pop($parts);
596+
$namespace = 'namespace ' . join('\\', $parts) . ';';
595597
}
596598

597599
$classTemplate->setVar(
598600
array(
599601
'namespace' => $namespace,
600-
'class_name' => $originalClassName,
602+
'class_name' => $className,
601603
'wsdl' => $wsdlFile,
602604
'options' => $optionsBuffer,
603605
'methods' => $methodsBuffer
@@ -614,33 +616,60 @@ public function generateClassFromWsdl($wsdlFile, $originalClassName, array $meth
614616
}
615617

616618
/**
617-
* @param string $originalClassName
618-
* @param array|null $methods
619-
* @param string $mockClassName
620-
* @param boolean $callOriginalClone
621-
* @param boolean $callAutoload
622-
* @param boolean $cloneArguments
623-
* @param boolean $callOriginalMethods
619+
* @param array|string $type
620+
* @param array|null $methods
621+
* @param string $mockClassName
622+
* @param boolean $callOriginalClone
623+
* @param boolean $callAutoload
624+
* @param boolean $cloneArguments
625+
* @param boolean $callOriginalMethods
624626
* @return array
625627
* @throws PHPUnit_Framework_Exception
626628
*/
627-
protected function generateMock($originalClassName, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods)
629+
protected function generateMock($type, $methods, $mockClassName, $callOriginalClone, $callAutoload, $cloneArguments, $callOriginalMethods)
628630
{
629631
$templateDir = dirname(__FILE__) . DIRECTORY_SEPARATOR . 'Generator' .
630632
DIRECTORY_SEPARATOR;
631633
$classTemplate = new Text_Template(
632634
$templateDir . 'mocked_class.tpl'
633635
);
634636

637+
635638
$additionalInterfaces = array();
636-
$cloneTemplate = '';
637-
$isClass = FALSE;
638-
$isInterface = FALSE;
639+
$cloneTemplate = '';
640+
$isClass = FALSE;
641+
$isInterface = FALSE;
639642

640643
$mockClassName = $this->generateClassName(
641-
$originalClassName, $mockClassName, 'Mock_'
644+
$type, $mockClassName, 'Mock_'
642645
);
643646

647+
if (is_array($type)) {
648+
foreach ($type as $_type) {
649+
if (!interface_exists($_type, $callAutoload)) {
650+
throw new PHPUnit_Framework_Exception(
651+
sprintf(
652+
'Interface "%s" does not exist.', $_type
653+
)
654+
);
655+
}
656+
657+
$additionalInterfaces[] = $_type;
658+
659+
foreach (get_class_methods($_type) as $method) {
660+
if (in_array($method, $methods)) {
661+
throw new PHPUnit_Framework_Exception(
662+
sprintf(
663+
'Duplicate method "%s" not allowed.', $method
664+
)
665+
);
666+
}
667+
668+
$methods[] = $method;
669+
}
670+
}
671+
}
672+
644673
if (class_exists($mockClassName['fullClassName'], $callAutoload)) {
645674
$isClass = TRUE;
646675
} else {
@@ -771,39 +800,43 @@ protected function generateMock($originalClassName, $methods, $mockClassName, $c
771800
}
772801

773802
/**
774-
* @param string $originalClassName
775-
* @param string $className
776-
* @param string $prefix
803+
* @param array|string $type
804+
* @param string $className
805+
* @param string $prefix
777806
* @return array
778807
*/
779-
protected function generateClassName($originalClassName, $className, $prefix)
808+
protected function generateClassName($type, $className, $prefix)
780809
{
781-
if ($originalClassName[0] == '\\') {
782-
$originalClassName = substr($originalClassName, 1);
810+
if (is_array($type)) {
811+
$type = join('_', $type);
812+
}
813+
814+
if ($type[0] == '\\') {
815+
$type = substr($type, 1);
783816
}
784817

785-
$classNameParts = explode('\\', $originalClassName);
818+
$classNameParts = explode('\\', $type);
786819

787820
if (count($classNameParts) > 1) {
788-
$originalClassName = array_pop($classNameParts);
789-
$namespaceName = join('\\', $classNameParts);
790-
$fullClassName = $namespaceName . '\\' . $originalClassName;
821+
$type = array_pop($classNameParts);
822+
$namespaceName = join('\\', $classNameParts);
823+
$fullClassName = $namespaceName . '\\' . $type;
791824
} else {
792825
$namespaceName = '';
793-
$fullClassName = $originalClassName;
826+
$fullClassName = $type;
794827
}
795828

796829
if ($className == '') {
797830
do {
798-
$className = $prefix . $originalClassName . '_' .
831+
$className = $prefix . $type . '_' .
799832
substr(md5(microtime()), 0, 8);
800833
}
801834
while (class_exists($className, FALSE));
802835
}
803836

804837
return array(
805838
'className' => $className,
806-
'originalClassName' => $originalClassName,
839+
'originalClassName' => $type,
807840
'fullClassName' => $fullClassName,
808841
'namespaceName' => $namespaceName
809842
);

0 commit comments

Comments
 (0)