我正在构建一个需要直接访问Composer的PHP应用程序。但是,为了测试应用程序,我实际上并不想运行作曲家,所以我试图模仿它。
<?php
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** @var Application|\PHPUnit_Framework_MockObject_MockObject $composer */
$composer = $this->getMockForAbstractClass(Application::class);
$composer
->expects($this->any())
->method('run')
->will($this->returnValue(true));
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
这实际上运行代码:
$ bin/phpunit -c phpunit-fast.xml tests/MyTest.php
PHPUnit 4.8.10 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.13-1+deb.sury.org~trusty+3 with Xdebug 2.3.2
Configuration: phpunit-fast.xml
Loading composer repositories with package information
Installing dependencies (including require-dev) from lock file
Nothing to install or update
Generating autoload files
我尝试了->getMock
(完全失败)和->getMockBuilder
的各种组合,但它似乎总是使用->run
方法而不是存根。
我认为它本身在某种程度上取代了这些方法,但如果是这样的话,我该怎样阻止呢?
有人问我为什么使用getMockForAbstractClass
而不仅仅是getMock
。使用getMock
时,我得到以下输出:
PHPUnit 4.8.10 by Sebastian Bergmann and contributors.
Runtime: PHP 5.6.13-1+deb.sury.org~trusty+3 with Xdebug 2.3.2
Configuration: phpunit.xml.dist
E
Time: 1.19 minutes, Memory: 4.50Mb
There was 1 error:
1) MyNamespace\MyTest::testComposer
PHPUnit_Framework_MockObject_RuntimeException: Cannot mock Symfony\Component\Console\Application::setDispatcher() because a class or interface used in the signature is not loaded
tests/MyTest.php:22
Caused by
ReflectionException: Class Symfony\Component\EventDispatcher\EventDispatcherInterface does not exist
tests/MyTest.php:22
FAILURES!
Tests: 1, Assertions: 0, Errors: 1.
尽管只使用$composer = new Application();
工作正常。事实上,如果我在测试之上添加该行,那么仍然声称class or interface
未加载var data = [];
for ( var x=0; x< 1000 ; x+=3*r) {
for ( var y=0; y< 1000 ; y+=3*r) {
data.push([x, y]);
}
}
svg.selectAll("circle").data(data).enter()
.append("circle")
.attr("cx", function(d) { return d[0]; })
.attr("cy", function(d) { return d[1]; })
.attr("r", r)
.attr("opacity", 0)
.transition()
.duration(100)
.delay(function(d, i) { return i * 100; })
.attr("opacity", 1);
,尽管该对象之前已正确实例化。
答案 0 :(得分:1)
我有3个解决方案:
添加&#34; symfony / event-dispatcher&#34;到你自己的require-dev
"require-dev" : {
...
"symfony/event-dispatcher" : "^2.1"
}
通过更正后的测试:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** @var Application|\PHPUnit_Framework_MockObject_MockObject $composer */
$composer = $this->getMock(Application::class);
$composer
->expects($this->any())
->method('run')
->will($this->returnValue(true));
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
个人注释: 这感觉就像是一个肮脏的黑客,但是迄今为止最简单的解决方案
使用预言与PHPUnit一起模拟控制台。
"require-dev" : {
...
"phpspec/prophecy": "~1.0"
}
现在测试看起来像这样:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Prophecy\Prophet;
use Prophecy\Prophecy\ObjectProphecy;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
$prophet = new Prophet();
$composerProphecy = $prophet->prophesize(Application::class);
$composerProphecy
->run(new ArrayInput(['command' => 'install']))
->willReturn(true);
/** @var Application $composer */
$composer = $composerProphecy->reveal();
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
}
}
个人提示: 我并不热衷于告诉预言使用魔术方法调用哪些方法,因为这会让我的IDE感到不安。
模拟系统的另一个选择。
"require-dev" : {
...
"mockery/mockery": "^0.9.4"
}
测试:
<?php
/**
* MyTest.php
*/
namespace MyNamespace;
use Composer\Console\Application;
use Symfony\Component\Console\Input\ArrayInput;
class MyTest extends \PHPUnit_Framework_TestCase {
public function testComposer()
{
/** @var Application|\Mockery\MockInterface $composer */
$composer = \Mockery::mock(Application::class);
$composer
->shouldReceive('run')
->with(ArrayInput::class)
->andReturn(true);
$this->assertTrue(
$composer->run(new ArrayInput(['command' => 'install']))
);
\Mockery::close();
}
}
个人注释: 静态使用,必须记住清理,以及shouldReceive
中使用可变参数的错误记录使我很伤心。
似乎不太可能,但如果有人可以解决如何修复#8200,那么这意味着没有人必须使用多个模拟框架(如果你已经使用过PHPUnit)或添加脏黑客他们的需求 - 开发一次破坏测试。
答案 1 :(得分:0)
我还不能发表评论,抱歉。 :/
TL; DR:getMock变体适合我。检查你的环境。
通过composer获取作曲家(在composer.json中需要&#34;作曲家/作曲家&#34;:&#34; @ dev&#34;)让测试(使用getMock)为我传递。
检查您正在使用的symfony版本(我的是2.7.4)以及您是否正在使用作曲家的phar版本(您可能不应该这样做)。