zf2 phpunit controller dependency - unit-testing

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);
// ....
}

Related

Symfony ignore mock in test service

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

Symfony: update many-to-many

I have Post and Tag entities with many-to-many relationship. In Post create and edit form there is a textbox where I can enter tags separated by comma relevant to that post. For example, when I enter tag1, tag2, tag3 for post with title 'Post1', the form will create post and tag entities and add these tags to tags list of that post.I use data transformer to create tag entities.
class Post{
/**
* #ORM\ManyToMany(targetEntity="Tag", mappedBy="posts",cascade={"all"})
*/
protected $tags;
public function __construct() {
$this->tags = new ArrayCollection();
}
/**
* #return ArrayCollection
*/
public function getTags()
{
return $this->tags;
}
/**
* #param Tag $tag
*/
public function addTag(Tag $tag)
{
$tag->addPost($this);
$this->tags->add($tag);
}
/**
* #param Tag $tag
*/
public function removeTag(Tag $tag)
{
$this->tags->removeElement($tag);
}
}
PostType
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title', TextType::class, array('label' => 'Title'))
->add('tags', TextType::class, array('label' => 'Tags'))
;
$builder->get('tags')
->addModelTransformer(new TagViewTransformer($this->manager));
}
TagViewTransformer
class TagViewTransformer implements DataTransformerInterface
{
public function transform($value)
{
/...
}
public function reverseTransform($value)
{
$tags = array();
if ( $value )
{
if( strpos($value, ',') !== false )
{
$list = array_unique(explode(",", $value));
}
else
{
$list = array(trim($value));
}
foreach ( $list AS $tagName )
{
$tag = $this->em
->getRepository('CoreBundle:Tag')
->findOneBy(array('name' => trim($tagName)));
if( !$tag )
{
$tag = new Tag();
$tag->setName(trim($tagName));
$this->em->persist($tag);
}
$tags[] = $tag;
}
}
return $tags;
}
}
This works fine when I try to create Post, all tags are transformed to entities and are added to Post's tags list. but when I try to edit, I start having problems
public function editAction(Request $request, Post $post)
{
$deleteForm = $this->createDeleteForm($post);
$editForm = $this->createForm(PostType::class, $post);
$editForm->handleRequest($request);
$originalTags = $post->getTags();
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$newTags = $editForm->get('tags')->getData();
foreach ($originalTags as $currentTag) {
if (!in_array($currentTag, $newTags)) {
$post->removeTag($currentTag);
}
}
$em->persist($post);
$em->flush();
return $this->redirectToRoute('post_show', array('id' => $post->getId()));
}
return $this->render('AppBundle:Post:edit.html.twig', array(
'entity' => $post,
'form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
Let's say Post has tags: tag1, tag2, tag3, but I want to remove tag3 and add tag4. So I will change tags textbox to tag1, tag2, tag4. However when I submit form, I get tag1, tag2, tag3, tag4. So tag3 is not removed from Post's tag list.
What is wrong with the editAction code?
try with this
public function editAction(Request $request, Post $post)
{
$deleteForm = $this->createDeleteForm($post);
$editForm = $this->createForm(PostType::class, $post);
$editForm->handleRequest($request);
if ($editForm->isSubmitted() && $editForm->isValid()) {
$em = $this->getDoctrine()->getManager();
$em->persist($post);
$em->flush();
return $this->redirectToRoute('post_show', array('id' => $post->getId()));
}
return $this->render('AppBundle:Post:edit.html.twig', array(
'entity' => $post,
'form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
));
}
Use Orphan removal to do this :
class Post
{
/**
* #ORM\ManyToMany(targetEntity="Tag", mappedBy="posts", cascade={"all"}, orphanRemoval=true)
*/
protected $tags;
/* Rest of your class */
}
Do some tests, maybe cascade all is not necessary here.

Custom Twig tag; could not find base class __TwigTemplate_

I'm trying to create a custom Twig tag (http://twig.sensiolabs.org/doc/advanced.html#tags) for my custom website system.
By using the following tag in a template:
{% entity '\\Testimonial\\Entity\\Testimonial' with { 'limit' : 2, 'column' : 'created' } %}
The custom tag will load the last 2 Testimonials from the database ordered by the column created. Ok, so far so good.
For the TokenParser I used code from the include tag:
class Entity extends Twig_TokenParser
{
public function parse(Twig_Token $token)
{
$object = $this -> parser -> getCurrentToken() -> getValue();
if( empty($object))
{
return;
}
$expr = $this->parser->getExpressionParser()->parseExpression();
$variables = $this->parseArguments();
return new EntityNode( $object, $expr, $variables, $token->getLine(), $this->getTag() );
}
protected function parseArguments()
{
$stream = $this->parser->getStream();
$variables = null;
if ($stream->test(Twig_Token::NAME_TYPE, 'with')) {
$stream->next();
$variables = $this->parser->getExpressionParser()->parseExpression();
}
$stream->expect(Twig_Token::BLOCK_END_TYPE);
return $variables;
}
public function getTag()
{
return "entity";
}
}
And for the Node I've borrowed from include and some other examples I've found resulting in:
class EntityNode extends Twig_Node implements Twig_NodeOutputInterface
{
public function __construct(
$object,
Twig_Node_Expression $expr,
Twig_Node_Expression $variables = null,
$lineno,
$tag = null )
{
parent::__construct(array('expr' => $expr, 'variables' => $variables), array("object" => $object), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$obj = $this->getAttribute('object');
if( !is_callable( $obj ) || !class_exists( $obj ))
{
// error not callable
}
$entities = forward_static_call( array( $obj , "TemplateEntity" ) , $this -> getNode( "variables" ));
$subtemplate = forward_static_call( array( $obj , "TemplateEntityTemplatePath" ));
$template = new Twig_Node_Expression_Constant( $subtemplate , $this -> getLine() );
#return;
$compiler
-> write("\$this->env->loadTemplate(")
-> subcompile($template)
-> raw(")")
;
}
}
The result is an error from Twig saying it can't load the basetemplate:
Parse error: syntax error, unexpected 'echo' (T_ECHO) in /domains/<domain>/lib/framework/vendors/twig/lib/Twig/Environment.php(328) : eval()'d code on line 370
0 - Exception occurred
Exception -- Autoloader could not find base class __TwigTemplate_c56f3794ae5aed2d0cc25529303a838625ded364d30febb96cd025a5d7622121
I know everything works correctly until the Twig_Node, the problem lies in how Twig parses the line $compiler
-> write("\$this->env->loadTemplate(")
-> subcompile($template)
-> raw(")")
;
Hope to get some help from you guys; any help is appreciated!
So in the end Twig has a weird way of formulating errors in the code.
After careful considering other Node examples in the Twig node directory I noted the following missing ; at the end of the compiler method raw:
class EntityNode extends Twig_Node implements Twig_NodeOutputInterface
{
public function __construct(
$object,
Twig_Node_Expression $expr,
Twig_Node_Expression $variables = null,
$lineno,
$tag = null )
{
parent::__construct(array('expr' => $expr, 'variables' => $variables), array("object" => $object), $lineno, $tag);
}
public function compile(Twig_Compiler $compiler)
{
$compiler->addDebugInfo($this);
$obj = $this->getAttribute('object');
if( !is_callable( $obj ) || !class_exists( $obj ))
{
// error not callable
}
$entities = forward_static_call( array( $obj , "TemplateEntity" ) , $this -> getNode( "variables" ));
$subtemplate = forward_static_call( array( $obj , "TemplateEntityTemplatePath" ));
$template = new Twig_Node_Expression_Constant( $subtemplate , $this -> getLine() );
#return;
$compiler
-> write("\$this->env->loadTemplate(")
-> subcompile($template)
-> raw(");\n")
;
}
}

Silex and Doctrine ORM

I am trying to use Silex together with Doctrine ORM (not just DBAL) but I am unable to get the configuration correct.
composer.json
{
"require": {
"silex/silex": "1.0.*#dev",
"symfony/monolog-bridge": "~2.1",
"symfony/twig-bridge": "~2.1",
"symfony/form": "~2.1",
"symfony/yaml": "2.2.*",
"symfony/form": "2.2.*",
"symfony/translation": "~2.1",
"symfony/config": "2.2.*",
"dflydev/doctrine-orm-service-provider": "1.0.*#dev"
},
"autoload": {
"psr-0": {
"Entities": "src/"
}
}
}
bootstrap.php located in my project root folder
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
require_once __DIR__ ."/vendor/autoload.php";
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src/Entities"), $isDevMode);
$params = array(
'driver' => 'pdo_sqlite',
'path' => __DIR__ . '/development.sqlite',
);
$entityManager = EntityManager::create($params, $config);
cli-config.php also located inside the root folder
require_once "bootstrap.php";
$helperSet = new \Symfony\Component\Console\Helper\HelperSet(array(
'db' => new \Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper($entityManager->getConnection()),
'em' => new \Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper($entityManager)
));
Customer.php entity located inside src/Entities
/**
* #Entity #Table(name="customers")
**/
class Customer {
/** #Id #Column(type="integer") #GeneratedValue **/
protected $id;
/** #Column(type="string") **/
protected $name;
public function getName() {
return $this->name;
}
public function setName($name) {
$this->name = $name;
}
public function getId() {
return $this->id;
}
}
I am able to run commands like php vendor/bin/doctrine orm:schema-tool:create and have it generate a table called customs just as it should. But how do I load that entity inside my Silex application
Here is my index.php
require_once __DIR__.'/../vendor/autoload.php';
$app = new Silex\Application();
use Symfony\Component\Yaml\Yaml;
$app['config'] = function () {
$config = Yaml::parse(__DIR__ .'/../config.yml');
return $config;
};
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
'dns.options' => $app['config']['database']['development']
));
$app->register(new Dflydev\Silex\Provider\DoctrineOrm\DoctrineOrmServiceProvider, array(
'orm.em.options' => array(
'mappings' => array(
array(
'type' => 'annotation',
'path' => __DIR__ .'/src/Entities',
)
)
),
));
$app->get('/', function () use ($app) {
$customer = $app['orm.em']->getRepository('Customer');
return '<pre>'. $customer->getName() .'</pre>';
});
The result when loading the localhost inside my browser
Warning: class_parents() [function.class-parents]: Class Customer does not exist and could not be loaded in /Users/me/Documents/project/vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php on line 40
UPDATE
I am not sure this is the correct way to solve this issue, but by using the following approach the problem got solved and I can now use my entities in Silex
$app['em'] = function ($app) {
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src/Entities"), true);
$params = array(
'driver' => 'pdo_sqlite',
'path' => __DIR__ . '/../development.sqlite',
);
$entityManager = EntityManager::create($params, $config);
return $entityManager;
};
I used the dependency approach because that way I can use $app['config'] to store DB information and other environment specific configurations.
$customer = new \Entities\Customer();
$customer->setName('Multi Corp '. uniqid());
$app['em']->persist($customer);
$app['em']->flush();
I presume your doctrine Entity mappings reside under "/src/Entities" in the namespace \Entities. With your autoloader directive they should be accessible as \Entities\MyMappingCls.
Your problem seems to be that you don't give the fq-name of the mapping class when getting the repository. You need to give a string that can be resolved by the autoloader. Please try:
$app['orm.em']->getRepository('Entities\Customer');
You can also try to run orm:generate-proxies as they are only generated on the fly in debug mode (not so sure this is relevant).
hth

Symfony2 - Tests with FOSUserBundle

i would write a test for Symfony2 with FOSUserBundle.
At the moment i tried some ways and no one works.
I need a function like "createAuthClient".
Here is my basic class.
I post it because you could understand my problem better.
<?php
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\BrowserKit\Cookie;
class WebTestMain extends WebTestCase
{
protected static $container;
static protected function createClient(array $options = array(), array $server = array())
{
$client = parent::createClient($options, $server);
self::$container = self::$kernel->getContainer();
return $client;
}
static function createAuthClient(array $options = array(), array $server = array())
{
// see lines below with my tries
}
}
First try:
if(static::$kernel === null)
{
static::$kernel = static::createKernel($options);
static::$kernel->boot();
}
if(static::$container === null)
{
self::$container = self::$kernel->getContainer();
}
$parameters = self::$container->getParameter('test');
$server = array_merge(array('HTTP_HOST' => $parameters['host'], 'HTTP_USER_AGENT' => $parameters['useragent']), $server);
$client = self::createClient($options, $server);
$userProvider = self::$container->get('fos_user.user_manager');
$user = $userProvider->findUserBy(array('id' => 1));
$client->getCookieJar()->set(new Cookie('MOCKSESSID', true));
$session = self::$kernel->getContainer()->get('session');
$token = new UsernamePasswordToken($user, null, 'main', $user->getRoles());
$client->getContainer()->get('security.context')->setToken($token);
$session->set('_security_main', serialize($token));
return $client;
Then i searched and searched...
My second try.
if(static::$kernel === null)
{
static::$kernel = static::createKernel($options);
static::$kernel->boot();
}
if(static::$container === null)
{
self::$container = self::$kernel->getContainer();
}
$parameters = self::$container->getParameter('test');
$server = array_merge(
array(
'HTTP_HOST' => $parameters['host'],
'HTTP_USER_AGENT' => $parameters['useragent'],
'PHP_AUTH_USER' => 'admin',
'PHP_AUTH_PW' => 'admin'
),
$server
);
$client = static::createClient(array(), array());
$client->followRedirects();
return $client;
And here is my last try before i post this question...
$client = self::createClient($options, $server);
$parameters = self::$container->getParameter('test');
$server = array_merge(
array(
'HTTP_HOST' => $parameters['host'],
'HTTP_USER_AGENT' => $parameters['useragent']
),
$server
);
$client->setServerParameters($server);
$usermanager = self::$container->get('fos_user.user_manager');
$testuser = $usermanager->createUser();
$testuser->setUsername('test');
$testuser->setEmail('test#mail.org');
$testuser->setPlainPassword('test');
$usermanager->updateUser($testuser);
return $client;
Thank you in Advance.
The best way I have found to test with an authenticated user is to just visit your login page and submit the form with user name and password you have loaded from a fixture. This may seem slow and cumbersome but will test what the user will actually do. You can even create your own method to make using it quick and easy.
public function doLogin($username, $password) {
$crawler = $this->client->request('GET', '/login');
$form = $crawler->selectButton('_submit')->form(array(
'_username' => $username,
'_password' => $password,
));
$this->client->submit($form);
$this->assertTrue($this->client->getResponse()->isRedirect());
$crawler = $this->client->followRedirect();
}
Create an AbstractControllerTest and create an authorized client on setUp() as follow:
<?php
// ...
use Symfony\Component\BrowserKit\Cookie;
abstract class AbstractControllerTest extends WebTestCase
{
/**
* #var Client
*/
protected $client = null;
public function setUp()
{
$this->client = $this->createAuthorizedClient();
}
/**
* #return Client
*/
protected function createAuthorizedClient()
{
$client = static::createClient();
$container = $client->getContainer();
$session = $container->get('session');
/** #var $userManager \FOS\UserBundle\Doctrine\UserManager */
$userManager = $container->get('fos_user.user_manager');
/** #var $loginManager \FOS\UserBundle\Security\LoginManager */
$loginManager = $container->get('fos_user.security.login_manager');
$firewallName = $container->getParameter('fos_user.firewall_name');
$user = $userManager->findUserBy(array('username' => 'REPLACE_WITH_YOUR_TEST_USERNAME'));
$loginManager->loginUser($firewallName, $user);
// save the login token into the session and put it in a cookie
$container->get('session')->set('_security_' . $firewallName,
serialize($container->get('security.context')->getToken()));
$container->get('session')->save();
$client->getCookieJar()->set(new Cookie($session->getName(), $session->getId()));
return $client;
}
}
NOTE: Please, replace the username with your test username.
Then, extends the AbstractControllerTest and use the global $client to make requests as follow:
class ControllerTest extends AbstractControllerTest
{
public function testIndexAction()
{
$crawler = $this->client->request('GET', '/admin/');
$this->assertEquals(
Response::HTTP_OK,
$this->client->getResponse()->getStatusCode()
);
}
}
This method tested and works fine