📜 ⬆️ ⬇️

DI, PHPUnit and setUp

Inversion of dependencies (Dependency Injection) is a very pleasant thing, in many respects making life easier for the developer. But it is also the reason for the appearance of such constructors:

public function __construct( \Psr\Log\LoggerInterface $logger, \Zend_Db_Adapter_Pdo_Abstract $dba, ISomeService $service, ... ) { $this->_logger = $logger; $this->_dba = $dba; $this->_service = $service; ... } 

Using setUp() in unit tests can make life easier if you need to create the same mock set several times to test various implementation features of the developed class.

Suppose we have a class with the above constructor. To mock the environment in a separate test method, you need to write something like this:

  /* create mocks */ $mLogger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)->getMock(); $mDba = $this->getMockBuilder(\Zend_Db_Adapter_Pdo_Abstract::class)->getMockForAbstractClass(); $mService = $this->getMockBuilder(\Vendor\Module\ISomeService::class)->disableOriginalConstructor()->getMock(); ... /* setup mocks behaviour */ ... /* */ $obj = new Demo($mLogger, $mDba, $mService, ...); $res = $obj->method($arg1, ...); $this->assert... 

If the number of dependencies in the object is high enough, and the functionality implemented by them is rather complicated, then the unit test can contain a fair amount of blocks with initialization of mock objects, whose behavior is then specialized in accordance with the requirements to be checked. And if the number of dependencies in the constructor has changed, then you have to add new mock-objects to each test method and redo each $obj = new Demo(...); .
')
Following the principle of DRY ( Don't Repeat Yourself ), one should focus the creation of mocks in one place, and then specialize their behavior depending on the testing conditions in the corresponding test method. This can be done using the setUp function. First, we create properties in PHPUnit for the test object itself and dependency mocks:

 private $mLogger; private $mDba; private $mService; private $obj 

and then we write in the setUp function, called before each test method, the re-initialization of mocks and objects:

 private function setUp() { $this->mLogger = $this->getMockBuilder(\Psr\Log\LoggerInterface::class)->getMock(); $this->mDba = $this->getMockBuilder(\Zend_Db_Adapter_Pdo_Abstract::class)->getMockForAbstractClass(); $this->mService = $this->getMockBuilder(\Vendor\Module\ISomeService::class)->disableOriginalConstructor()->getMock(); ... $this->obj = new Demo($this->mLogger, $this->mDba, $this->mService, ...); } 

after which we specialize the mock behavior we need in the corresponding testing function:

 public function test_method() { /* setup mocks behaviour */ $this->mLogger->expects... ... $res = $this->obj->method(); } 

Special thanks to Fesor for the tip, that it is better to use setUp() , and not a crutch with extract() .

Source: https://habr.com/ru/post/277867/


All Articles