I'm trying to test a service using phpunit. When i mock a function in my StatServiceTest, my service ignore the mock i did.
with an example will be more clear :
my service.yml
my_service:
class: '%my_service.class%'
parent: parent_service
arguments:
- '#service.repository.commutation'
- '#service.repository.stat'
- '#service.repository.switchboard'
- '%sunrise_host%'
my service : StatService.php
class StatService extends AbstractService
{
protected $commutationRepository;
protected $statRepository;
protected $switchboardRepository;
protected $sunrise_host;
public function __construct(CommutationRepository $commutationRepository, StatRepository $statRepository, SwitchboardRepository $switchboardRepository, $sunrise_host)
{
$this->commutationRepository = $commutationRepository;
$this->statRepository = $statRepository;
$this->switchboardRepository = $switchboardRepository;
$this->sunrise_host = $sunrise_host;
}
public function getNightsWithSunService($id, $start, $end)
{
$switchboard = $this->switchboardRepository->getById($id);
$parameters = array(
'begin' => (int) $start,
'end' => (int) $end,
'lat' => (float) $switchboard->getElement()->getCoordinate()->getLat(),
'lng' => (float) $switchboard->getElement()->getCoordinate()->getLng(),
'timezone' => $switchboard->getElement()->getCoordinate()->getTimezone(),
);
$buzz = new Buzz();
$result = $buzz->post(
$this->sunrise_host.'/nights',
array(
'Content-Type' => 'application/json',
),
json_encode($parameters)
);
return json_decode($result->getContent(), true);
}
}
and finally my StatServiceTest.php
class StatServiceTest extends WebTestCase
{
public function testGetNightsWithSunService()
{
$dic = $this->_client->getKernel()->getContainer();
$sunriseHost = $dic->getParameter('sunrise_host');
$id = 426;
$start = 1538400421;
$end = 1538569621;
$mapNights = $this->getNights();
$mockStatService = $this->getMockBuilder("StatService")
->disableOriginalConstructor()
->getMock();
$mockStatService
->expects($this->any())
->method('getNightsWithSunService')
->withConsecutive(array($id, $start, $end))
->willReturnOnConsecutiveCalls($mapNights)
;
$statService = new StatService($mockCommutationRepository,
$mockStatRepository, $mockSwitchboardRepository, $sunriseHost);
$result = $statService->getNightsWithSunService($id, $start, $end);
$nights = array(
array(
'start' => 1538414415,
'end' => 1538458643,
),
array(
'start' => 1538500702,
'end' => 1538545117,
),
);
$this->assertTrue($this->arrays_are_similar($nights, $result));
}
public function getNights()
{
$nights = array(
array(
'start' => 1538414415,
'end' => 1538458643,
),
array(
'start' => 1538500702,
'end' => 1538545117,
),
);
return $nights;
}
public function arrays_are_similar($a, $b)
{
// we know that the indexes, but maybe not values, match.
// compare the values between the two arrays
foreach ($a as $k => $v) {
if ($v !== $b[$k]) {
return false;
}
}
// we have identical indexes, and no unequal values
return true;
}
}
the error is :
testGetNightsWithSunService
Buzz\Exception\RequestException:
file_get_contents(http://localhost:4244/nights): failed to open
stream: Connection refused
i instantiate my service and i inject in it repositories that i mocked, i just put the part of code that concerns the problem.
What i did wrong ? please any advice will be helpful
The solution i founded is to do another service => toolsService with a function callback for the buzz part, and then we can inject this service and will be more easy to mock it.
I hope that will help you
Related
I'm using PS 1.6.1.16 and I'm wondering if there is a way to display "additional" or "different" content on product.tpl if the product type is "Virtual" (set in BO).
Additionally, is there a way to create a category page for all these "Virtual" products?
Thanks in advance.
In tpl condition is :
{if $product->is_virtual} IS VIRTUAL PRODUCT {else} NO VIRTUAL PRODUCT {/if}
To have a dedicated page is different, here is an example of product override to put in ROOT/override/controllers/front/ProductController.php which allows you to load a new TPL for virtual products. It is therefore necessary in the theme to add a product_virtual.tpl file
<?php
class ProductController extends ProductControllerCore
{
public function initContent()
{
parent::initContent();
if (!$this->errors) {
if (Pack::isPack((int)$this->product->id) && !Pack::isInStock((int)$this->product->id)) {
$this->product->quantity = 0;
}
$this->product->description = $this->transformDescriptionWithImg($this->product->description);
// Assign to the template the id of the virtual product. "0" if the product is not downloadable.
$this->context->smarty->assign('virtual', ProductDownload::getIdFromIdProduct((int)$this->product->id));
$this->context->smarty->assign('customizationFormTarget', Tools::safeOutput(urldecode($_SERVER['REQUEST_URI'])));
if (Tools::isSubmit('submitCustomizedDatas')) {
// If cart has not been saved, we need to do it so that customization fields can have an id_cart
// We check that the cookie exists first to avoid ghost carts
if (!$this->context->cart->id && isset($_COOKIE[$this->context->cookie->getName()])) {
$this->context->cart->add();
$this->context->cookie->id_cart = (int)$this->context->cart->id;
}
$this->pictureUpload();
$this->textRecord();
$this->formTargetFormat();
} elseif (Tools::getIsset('deletePicture') && !$this->context->cart->deleteCustomizationToProduct($this->product->id, Tools::getValue('deletePicture'))) {
$this->errors[] = Tools::displayError('An error occurred while deleting the selected picture.');
}
$pictures = array();
$text_fields = array();
if ($this->product->customizable) {
$files = $this->context->cart->getProductCustomization($this->product->id, Product::CUSTOMIZE_FILE, true);
foreach ($files as $file) {
$pictures['pictures_'.$this->product->id.'_'.$file['index']] = $file['value'];
}
$texts = $this->context->cart->getProductCustomization($this->product->id, Product::CUSTOMIZE_TEXTFIELD, true);
foreach ($texts as $text_field) {
$text_fields['textFields_'.$this->product->id.'_'.$text_field['index']] = str_replace('<br />', "\n", $text_field['value']);
}
}
$this->context->smarty->assign(array(
'pictures' => $pictures,
'textFields' => $text_fields));
$this->product->customization_required = false;
$customization_fields = $this->product->customizable ? $this->product->getCustomizationFields($this->context->language->id) : false;
if (is_array($customization_fields)) {
foreach ($customization_fields as $customization_field) {
if ($this->product->customization_required = $customization_field['required']) {
break;
}
}
}
// Assign template vars related to the category + execute hooks related to the category
$this->assignCategory();
// Assign template vars related to the price and tax
$this->assignPriceAndTax();
// Assign template vars related to the images
$this->assignImages();
// Assign attribute groups to the template
$this->assignAttributesGroups();
// Assign attributes combinations to the template
$this->assignAttributesCombinations();
// Pack management
$pack_items = Pack::isPack($this->product->id) ? Pack::getItemTable($this->product->id, $this->context->language->id, true) : array();
$this->context->smarty->assign('packItems', $pack_items);
$this->context->smarty->assign('packs', Pack::getPacksTable($this->product->id, $this->context->language->id, true, 1));
if (isset($this->category->id) && $this->category->id) {
$return_link = Tools::safeOutput($this->context->link->getCategoryLink($this->category));
} else {
$return_link = 'javascript: history.back();';
}
$accessories = $this->product->getAccessories($this->context->language->id);
if ($this->product->cache_is_pack || count($accessories)) {
$this->context->controller->addCSS(_THEME_CSS_DIR_.'product_list.css');
}
if ($this->product->customizable) {
$customization_datas = $this->context->cart->getProductCustomization($this->product->id, null, true);
}
$this->context->smarty->assign(array(
'stock_management' => Configuration::get('PS_STOCK_MANAGEMENT'),
'customizationFields' => $customization_fields,
'id_customization' => empty($customization_datas) ? null : $customization_datas[0]['id_customization'],
'accessories' => $accessories,
'return_link' => $return_link,
'product' => $this->product,
'product_manufacturer' => new Manufacturer((int)$this->product->id_manufacturer, $this->context->language->id),
'token' => Tools::getToken(false),
'features' => $this->product->getFrontFeatures($this->context->language->id),
'attachments' => (($this->product->cache_has_attachments) ? $this->product->getAttachments($this->context->language->id) : array()),
'allow_oosp' => $this->product->isAvailableWhenOutOfStock((int)$this->product->out_of_stock),
'last_qties' => (int)Configuration::get('PS_LAST_QTIES'),
'HOOK_EXTRA_LEFT' => Hook::exec('displayLeftColumnProduct'),
'HOOK_EXTRA_RIGHT' => Hook::exec('displayRightColumnProduct'),
'HOOK_PRODUCT_OOS' => Hook::exec('actionProductOutOfStock', array('product' => $this->product)),
'HOOK_PRODUCT_ACTIONS' => Hook::exec('displayProductButtons', array('product' => $this->product)),
'HOOK_PRODUCT_TAB' => Hook::exec('displayProductTab', array('product' => $this->product)),
'HOOK_PRODUCT_TAB_CONTENT' => Hook::exec('displayProductTabContent', array('product' => $this->product)),
'HOOK_PRODUCT_CONTENT' => Hook::exec('displayProductContent', array('product' => $this->product)),
'display_qties' => (int)Configuration::get('PS_DISPLAY_QTIES'),
'display_ht' => !Tax::excludeTaxeOption(),
'jqZoomEnabled' => Configuration::get('PS_DISPLAY_JQZOOM'),
'ENT_NOQUOTES' => ENT_NOQUOTES,
'outOfStockAllowed' => (int)Configuration::get('PS_ORDER_OUT_OF_STOCK'),
'errors' => $this->errors,
'body_classes' => array(
$this->php_self.'-'.$this->product->id,
$this->php_self.'-'.$this->product->link_rewrite,
'category-'.(isset($this->category) ? $this->category->id : ''),
'category-'.(isset($this->category) ? $this->category->getFieldByLang('link_rewrite') : '')
),
'display_discount_price' => Configuration::get('PS_DISPLAY_DISCOUNT_PRICE'),
));
}
if (ProductDownload::getIdFromIdProduct((int)$this->product->id) == 0)
$this->setTemplate(_PS_THEME_DIR_.'product.tpl');
else
$this->setTemplate(_PS_THEME_DIR_.'product_virtual.tpl');
}
}
I want to test a controller using a mock.
In my controller
public function myAction() {
$email = new MandrillApi(['template_name'=>'myTemplate']);
$result = $email
->subject('My title')
->from('no-reply#test.com')
->to('dest#test.com')
->send();
if ( isset($result[0]['status']) && $result[0]['status'] === 'sent' )
return $this->redirect(['action' => 'confirmForgotPassword']);
$this->Flash->error(__("Error"));
}
In test
public function testMyAction() {
$this->get("users/my-action");
$this->assertRedirect(['controller' => 'Users', 'action' => 'confirmForgotPassword']);
}
How do I mock the class MandrillApi ? thank you
In your controller-test:
public function controllerSpy($event){
parent::controllerSpy($event);
if (isset($this->_controller)) {
$MandrillApi = $this->getMock('App\Pathtotheclass\MandrillApi', array('subject', 'from', 'to', 'send'));
$this->_controller->MandrillApi = $MandrillApi;
$result = [
0 => [
'status' => 'sent'
]
];
$this->_controller->MandrillApi
->method('send')
->will($this->returnValue($result));
}
}
The controllerSpy method will insert the mocked object once the controller is setup correctly. You don't have to call the controllerSpy method, it gets executed automatically at some point after you make the $this->get(... call in your test.
Obviously you have to change the App\Pathtotheclass-part of the mock-generation to fit the location of your MandrillApi-class.
i'm a little stuck trying to test my users-controller in cakephp,
i have an action wich sends an email to a certain email address.
The email utility works, no problem whatsoever.
I want to mock the email utility so that when i test the action (with "testAction"),
no email will be sent.
I already searched all over stackoverflow and tried a lot of solutions, the current code is like follows:
UsersController:
/**
* Get Email Utility, use method so that unit testing is possible
* #return object
*/
public function _getEmailer()
{
return new CakeEmail();
}
public function lostPassword()
{
if($this->request->is('post'))
{
$email = $this->request->data['User']['email'];
$this->User->recursive = -1;
$user = $this->User->find('first', array('conditions' => array('email' => $email)));
if(!$user)
{
$this->Session->setFlash('Error: user not found');
return $this->render();
}
$recoverTrials = $this->User->Recover->find('count', array('conditions' => array('email' => $email)));
if($recoverTrials > 3)
{
$this->Session->setFlash(__('message.recover-too-many'));
return $this->redirect('/');
}
// Generate random key to reset password
$key = md5(microtime().rand());
$data = array('user_id' => $user['User']['id'],
'key' => $key,
'active' => 1,
'created' => date('Y-m-d H:i:s'));
if(!$this->User->Recover->save($data))
{
$this->Session->setFlash('Error while sending the recovery-mail');
return $this->redirect('/');
}
$this->Email = $this->_getEmailer();
$this->Email->emailFormat('html');
$this->Email->to($email);
$this->Email->subject('Password recover');
$this->Email->replyTo('noreply#domain.com');
$this->Email->from(array('noreply#domain.com' => 'Sender ID'));
$this->Email->template('recover');
$this->Email->viewVars(array('key' => $key)); // Set variables for template
try
{
$this->Email->send();
}
catch(Exception $e)
{
$this->Session->setFlash('Error while sending the recovery-mail');
return $this->render();
}
$this->Session->setFlash('The recovery mail with instructions to reset your password has been sent. Please note that the link will only remain active for 2 hours.');
return $this->redirect('/');
}
}
And my test class looks like (excerpt):
public function testPostLostPassword()
{
$this->Controller = $this->generate('Users', array(
'methods' => array(
'_getEmailer'
),
'components' => array('Security')
));
$emailer = $this->getMock('CakeEmail', array(
'to',
'emailFormat',
'subject',
'replyTo',
'from',
'template',
'viewVars',
'send'
));
$emailer->expects($this->any())
->method('send')
->will($this->returnValue(true));
$this->Controller->expects($this->any())
->method('_getEmailer')
->will($this->returnValue($emailer));
Correct email
$data = array('User' => array('email' => 'me#domain.com'));
$result = $this->testAction('/lostPassword', array('method' => 'post',
'data' => $data,
'return' => 'contents'));
}
What am i doing wrong? The Email utility still sends out the email to my address, even though i mocked it...
Thanks in advance!
I want to test a model and for one of those tests I want to mock a method of the model I am testing. So I don't test a controller and I don't want to replace a whole model, just one method of the same model I test.
Reason is that this model method calls a file upload handler. This feature is already tested elsewhere.
What I am doing now is:
I test the model 'Content'. There I test it's method 'addTeaser', which calls 'sendTeaser'.
SO I want to mock sendTeaser and fake a successful answer of the method sendTeaser, while testing addTeaser.
That looks like this:
$model = $this->getMock('Content', array('sendTeaser'));
$model->expects($this->any())
->method('sendTeaser')
->will($this->returnValue(array('ver' => ROOT.DS.APP_DIR.DS.'webroot/img/teaser/5/555_ver.jpg')));
$data = array(
'Content' => array(
'objnbr' => '555',
'name' => '',
...
)
)
);
$result = $model->addTeaser($data);
$expected = true;
$this->assertEquals($expected, $result);
When I let my test run, I get an error that a model within the method 'sendTeaser' is not called properly. Hey! It shouldn't be called! I mocked the method!
..... or not?
What would be the proper syntax for mocking the method?
Thanks a lot as always for help!
Calamity Jane
Edit:
Here is the relevant code for my model:
App::uses('AppModel', 'Model');
/**
* Content Model
*
* #property Category $Category
*/
class Content extends AppModel {
public $dateipfad = '';
public $fileName = '';
public $errormessage = '';
public $types = array(
'sqr' => 'square - more or less squarish',
'hor' => 'horizontal - clearly wider than high',
'lnd' => 'landscape - low but very wide',
'ver' => 'column - clearly higher than wide',
);
public $order = "Content.id DESC";
public $actsAs = array('Containable');
public $validateFile = array(
'size' => 307200,
'type' => array('jpeg', 'jpg'),
);
//The Associations below have been created with all possible keys, those that are not needed can be removed
public $hasMany = array(
'CategoriesContent' => array(
'className' => 'CategoriesContent',
),
'ContentsTag' => array(
'className' => 'ContentsTag',
),
'Description' => array(
'className' => 'Description',
)
);
/**
* Saves the teaser images of all formats.
*
* #param array $data
*
* #return Ambigous <Ambigous, string, boolean>
*/
public function addTeaser($data)
{
$objnbr = $data['Content']['objnbr'];
$type = $data['Content']['teaser-type'];
if (!empty($data['Content']['teaser-img']['tmp_name'])) {
$mFileNames = $this->sendTeaser($data, $objnbr, $type);
}
if (!is_array($mFileNames)) {
$error = $mFileNames;
//Something failed. Remove the image uploaded if any.
$this->deleteMovedFile(WWW_ROOT.IMAGES_URL.$mFileNames);
return $error;
}
return true;
}
/**
* Define imagename and save the file under this name.
*
* Since we use Imagechache, we don't create a small version anymore.
*
* #param integer $objnbr
* #param string $teasername
*
* #return multitype:Ambigous <string, boolean> |Ambigous <boolean, string>
*/
public function sendTeaser($data, $objnbr, $type)
{
//$path = str_replace('htdocs','tmp',$_SERVER['DOCUMENT_ROOT']);
$this->fileName = $this->getImageName($objnbr, $type);
$oUH = $this->getUploadHandler($data['Content']['teaser-img']);
debug($oUH);
exit;
$error = $oUH->handleFileUpload();
if (empty($type))
$type = 0;
if ($error === 'none'){
// Send to ImageChacheServer
$oICC = $this->getImagecacheConnector();
$sCacheUrl = $oICC->uploadFile($objnbr, $type, $this->fileName);
debug($sCacheUrl);
return array($type => $this->fileName);
}
return $error;
}
public function getUploadHandler($imgdata)
{
App::uses('UploadHandler', 'Lib');
$oUH = new UploadHandler($this, $imgdata);
return $oUH;
}
}
Changing getMock to getMockForModel didn't change the output though.
I'd like to emphasize the answer from #ndm using Cake test helper class CakeTestCase::getMockForModel()
$theModel = CakeTestCase::getMockForModel('Modelname', ['theMethodToMock']);
$theModel->expects($this->once())
->method('theMethodToMock')
->will($this->returnValue('valueToReturn'));
$this->getMock is not the way to mock. You should use $this->generate
I would reccomend you to read a book about CakePHP unti testing, like this: https://leanpub.com/cakephpunittesting
I'm unit testing my controller called IndexController (used the http://framework.zend.com/manual/2.1/en/user-guide/modules.html tutorial).
My IndexController has a dependency:Translator $translator.
<?php
// module/Application/src/Application/Controller/IndexController.php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Zend\I18n\Translator\Translator;
class IndexController extends AbstractActionController
{
protected $translator;
public function __construct(Translator $translator)
{
$this->translator = $translator;
}
public function indexAction()
{
$steeringWheelMapper = $this->getServiceLocator()->get('SupplierName\Mapper\SteeringWheel');
$carBrandList = $steeringWheelMapper ->fetchCarBrandList();
return new ViewModel();
}
}
My unit test setup:
module
Application
test
ApplicationTest
Controller
IndexControllerTest.php
Bootstrap.php
phpunit.xml.dist
TestConfig.php.dist
Testing now gives the following error:
Argument 1 passed to Application\Controller\IndexController::__construct() must be an instance of Zend\I18n\Translator\Translator, none given.
Nothing strange here, but I can't find out where to add the translator object..
Where should I add the translator object?
The code
<?php
// module/Application/test/Testconfig.php.dist
return array(
'modules' => array(
'Application',
),
'module_listener_options' => array(
'config_glob_paths' => array(
'../../../config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'module',
'vendor',
),
),
);
<?php
// module/Application/test/Bootstrap.php
namespace ApplicationTest;//Change this namespace for your test
use Zend\Loader\AutoloaderFactory;
use Zend\Mvc\Service\ServiceManagerConfig;
use Zend\ServiceManager\ServiceManager;
use Zend\Stdlib\ArrayUtils;
use RuntimeException;
error_reporting(E_ALL | E_STRICT);
chdir(__DIR__);
class Bootstrap
{
protected static $serviceManager;
protected static $config;
protected static $bootstrap;
public static function init()
{
// Load the user-defined test configuration file, if it exists; otherwise, load
if (is_readable(__DIR__ . '/TestConfig.php')) {
$testConfig = include __DIR__ . '/TestConfig.php';
} else {
$testConfig = include __DIR__ . '/TestConfig.php.dist';
}
$zf2ModulePaths = array();
if (isset($testConfig['module_listener_options']['module_paths'])) {
$modulePaths = $testConfig['module_listener_options']['module_paths'];
foreach ($modulePaths as $modulePath) {
if (($path = static::findParentPath($modulePath)) ) {
$zf2ModulePaths[] = $path;
}
}
}
$zf2ModulePaths = implode(PATH_SEPARATOR, $zf2ModulePaths) . PATH_SEPARATOR;
$zf2ModulePaths .= getenv('ZF2_MODULES_TEST_PATHS') ?: (defined('ZF2_MODULES_TEST_PATHS') ? ZF2_MODULES_TEST_PATHS : '');
static::initAutoloader();
// use ModuleManager to load this module and it's dependencies
$baseConfig = array(
'module_listener_options' => array(
'module_paths' => explode(PATH_SEPARATOR, $zf2ModulePaths),
),
);
$config = ArrayUtils::merge($baseConfig, $testConfig);
$serviceManager = new ServiceManager(new ServiceManagerConfig());
$serviceManager->setService('ApplicationConfig', $config);
$serviceManager->get('ModuleManager')->loadModules();
static::$serviceManager = $serviceManager;
static::$config = $config;
}
public static function getServiceManager()
{
return static::$serviceManager;
}
public static function getConfig()
{
return static::$config;
}
protected static function initAutoloader()
{
$vendorPath = static::findParentPath('vendor');
if (is_readable($vendorPath . '/autoload.php')) {
$loader = include $vendorPath . '/autoload.php';
} else {
$zf2Path = getenv('ZF2_PATH') ?: (defined('ZF2_PATH') ? ZF2_PATH : (is_dir($vendorPath . '/ZF2/library') ? $vendorPath . '/ZF2/library' : false));
if (!$zf2Path) {
throw new RuntimeException('Unable to load ZF2. Run `php composer.phar install` or define a ZF2_PATH environment variable.');
}
include $zf2Path . '/Zend/Loader/AutoloaderFactory.php';
}
AutoloaderFactory::factory(array(
'Zend\Loader\StandardAutoloader' => array(
'autoregister_zf' => true,
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/' . __NAMESPACE__,
),
),
));
}
protected static function findParentPath($path)
{
$dir = __DIR__;
$previousDir = '.';
while (!is_dir($dir . '/' . $path)) {
$dir = dirname($dir);
if ($previousDir === $dir) return false;
$previousDir = $dir;
}
return $dir . '/' . $path;
}
}
Bootstrap::init();
<?php
// module/Application/test/ApplicationTest/Controller/IndexControllerTest.php
namespace ApplicationTest\Controller;
use ApplicationTest\Bootstrap;
use Zend\Mvc\Router\Http\TreeRouteStack as HttpRouter;
use Application\Controller\IndexController;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
use PHPUnit_Framework_TestCase;
class IndexControllerTest extends \PHPUnit_Framework_TestCase
{
protected $controller;
protected $request;
protected $response;
protected $routeMatch;
protected $event;
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new IndexController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setServiceLocator($serviceManager);
}
public function testIndexActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'index');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
}
}
Inject it in your setUp method
protected function setUp()
{
// ...
$translator = new \Zend\I18n\Translator;
$this->controller = new IndexController($translator);
// ....
}