我目前正在尝试做的是在单元测试中测试类的构造函数。
我不确定这个对象的实例是否是“上帝对象”,我会说不是,因为它只聚合了几个其他组件。
无论哪种方式,我都对更好的设计持开放态度。
粗略的类图看起来像这样
World
是可疑的神类。它的依赖项ServiceProvider
、Command d注册表
、EventHub
和环境
是通过它的构造函数注入的。
在其构造函数中,World
执行以下操作:
eventHub
注册一个钩子($this,'onCommand dIsted')
,以便world
接收有关所有正在执行的命令的通知,而不是通过world
实例本身(world
也有一个方法执行命令
)$this-
也许这看起来像一个沉重的构造函数,但它只是被定义为“构建世界”。
World
基本上是发送命令的网关(作为数据传输对象,通过World::executeCommand()
),不同的服务可以向其注册挂钩。
现在到问题/问题:
@使用
注释,这使得它感觉就像除了单元测试之外的其他任何东西。那么它是什么,功能测试?单元测试World
很尴尬,测试其他任何东西都非常琐碎,我在任何其他测试中都没有看到这个问题出现,这让我问自己为什么会这样,以及如何改进设计。World
是上帝对象吗?它所做的只是聚合其他组件并将调用转发给它们。World
的方法进行单元测试?如果我使用大量存根并依赖注入它们,它仍然是单元测试吗?这适用于领域驱动的设计(复杂)应用程序,我愿意接受使设计更好(可测试和解耦)的建议。
如果您需要更多详细信息,请在评论中告诉我。
由于我不知道这次讨论会导致什么,我可能会细化我的问题。
我终于通过设置正确的期望和模拟依赖关系来对类进行单元测试:
<?php
namespace Common\World;
use TestFramework\TestCase;
class WorldTest extends TestCase
{
/**
* @test
* @covers \Common\World\World::__construct
* @uses \Common\World\World::setEventHub
* @uses \Common\World\Event\Adopted
*/
public function construction()
{
/** @var \Common\World\Environment $environmentStub |\PHPUnit_Framework_MockObject_MockObject */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
/** @var \Common\World\EventHub|\PHPUnit_Framework_MockObject_MockObject $eventHubStub */
$eventHubStub = $this->getMock('Common\World\EventHub');
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnCallback(function (World $world) use ($eventHubStub) {
$world->setEventHub($eventHubStub);
return true;
}));
$eventHubStub->expects($this->once())
->method('trigger')
->with($this->isInstanceOf('Common\World\Event\Adopted'));
$this->assertInstanceOf('Common\World\World', new World($environmentStub));
}
/**
* @test
* @covers \Common\World\World::__construct
* @expectedException \RuntimeException
* @expectedExceptionMessage the environment has rejected this world for incompatibility reasons
*/
public function construction_rejected()
{
/** @var \Common\World\Environment $environmentStub */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnValue(false));
new World($environmentStub);
}
}