I am trying to test a method on the bind event of a custom form type.
Here is the code
public function bind(DataEvent $event)
{
$form = $event->getForm();
if($form->getNormData() instanceof BaseFileInterface && !$event->getData() instanceof UploadedFile) {
$event->setData($form->getNormData());
}
if($event->getData() instanceof UploadedFile) {
$hander = $this->handlerManager->getHandler(
$form->getParent()->getConfig()->getDataClass(),
$form->getName()
);
$datas = $hander->createBaseFile($event->getData());
$event->setData($datas);
}
if(is_string($event->getData())) {
$event->setData(null);
}
}
and the form builder of the type :
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->addEventSubscriber(new BaseFileListener($this->handlerManager))
->addViewTransformer(new BaseFileToStringTransformer())
;
}
My test class inherits from Symfony\Component\Form\Tests\FormIntegrationTestCase and is doing this :
protected function setUp()
{
parent::setUp();
$this->handlerManager = $this->getHandlerManagerMock();
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
$this->form = $this->factory->create('my_file');
$this->form->setParent($this->getFormMock())->setData(new DummyEntity());
}
protected function getFormMock()
{
$mock = $this
->getMockBuilder('Symfony\Component\Form\Tests\FormInterface')
->disableOriginalConstructor()
->getMock()
;
return $mock;
}
public function testBindHandleNewFileWithNonEmptyField()
{
$data = $file = new UploadedFile(
__DIR__.'/../Fixtures/test.gif',
'original.gif',
'image/gif',
filesize(__DIR__.'/../Fixtures/test.gif'),
null
);
$event = new FormEvent($this->form, $data);
$listener = new BaseFileListener($this->handlerManager);
$listener->bind($event);
$this->assertInstanceOf('My\FooBundle\Entity\BaseFileInterface', $event->getData());
$this->assertNotEquals($event->getData(), $this->form->getNormData());
}
The probleme is that the $form->getParent()->getConfig()->getDataClass() throws an exception on getDataClass ().
The question is how to build the form correctly to perform the bind test ?
Ok, answering my self :)
Here is the good mocking in phpunit :
protected function setUp()
{
parent::setUp();
$this->handlerManager = $this->getHandlerManagerMock();
$this->dispatcher = $this->getMock('Symfony\Component\EventDispatcher\EventDispatcherInterface');
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
$this->form = $this->factory->create('my_file');
$this->form->setParent($this->getFormMock());
}
protected function getFormMock()
{
$mock = $this->getMock('Symfony\Component\Form\Tests\FormInterface');
$mock
->expects($this->any())
->method('getConfig')
->will($this->returnValue($this->getFormConfigMock()))
;
return $mock;
}
protected function getFormConfigMock()
{
$mock = $this->getMockBuilder('Symfony\Component\Form\FormConfigInterface')
->disableOriginalConstructor()
->getMock();
$mock
->expects($this->any())
->method('getDataClass')
->will($this->returnValue('My\FooBundle\Tests\DummyEntity'))
;
return $mock;
}
I thought I could manage to rebuild the entire form without using mock, but it seems impossible.
If someone has a better solution to offer I'm interested.
Related
I'm new to test, I'm using codeception and phpunit to do some TDD.
However, my methods have a lot of code. Do I used best practices ? Is there a way to improve the readiness of my code, can it be more clean ?
class NewsFormHandlerTest extends \Codeception\Test\Unit
{
/**
* #var \UnitTester
*/
protected $tester;
protected function _before()
{
}
protected function _after()
{
}
private function getFormMock(){
return $this->getMockBuilder(FormInterface::class)
->disableOriginalConstructor()
->getMock();
}
private function getNewsManagerMock(){
return $this->getMockBuilder(INewsManager::class)
->disableOriginalConstructor()
->getMock();
}
// tests
public function testShouldHandleASuccessfulFormSubmissionForAddANews()
{
// prepare
$request = new \Symfony\Component\HttpFoundation\Request();
$news = new News();
$form = $this->getFormMock();
$form->expects($this->once())
->method('isValid')
->will($this->returnValue(true));
$form->expects($this->once())
->method('submit');
$form->expects($this->once())
->method('getData')
->will($this->returnValue($news));
$newsManager = $this->getNewsManagerMock();
$newsManager->expects($this->once())
->method('add');
$user = Stub::make(WebserviceUser::class, []);
// test
$handler = new NewsFormHandler($newsManager, $user);
$newsReturned = $handler->handle($form, $request, NewsFormHandler::ADD);
// assert
$this->assertInstanceOf(News::class, $newsReturned);
$this->assertEquals($news, $newsReturned);
}
public function testShouldHandleASuccessfulFormSubmissionForEditANews()
{
// prepare
$request = new \Symfony\Component\HttpFoundation\Request();
$news = new News();
$form = $this->getFormMock();
$form->expects($this->once())
->method('isValid')
->will($this->returnValue(true));
$form->expects($this->once())
->method('submit');
$form->expects($this->once())
->method('getData')
->will($this->returnValue($news));
$newsManager = $this->getNewsManagerMock();
$newsManager->expects($this->once())
->method('edit');
$user = Stub::make(WebserviceUser::class, []);
// test
$handler = new NewsFormHandler($newsManager, $user);
$newsReturned = $handler->handle($form, $request, NewsFormHandler::EDIT);
// assert
$this->assertInstanceOf(News::class, $newsReturned);
$this->assertEquals($news, $newsReturned);
}
public function testFailFormWithInvalidData()
{
// prepare
$request = new \Symfony\Component\HttpFoundation\Request();
$form = $this->getFormMock();
$form->expects($this->once())
->method('isValid')
->will($this->returnValue(false));
$newsManager = $this->getNewsManagerMock();
$newsManager->expects($this->never())
->method('edit');
$this->expectException(InvalidFormException::class);
$user = Stub::make(WebserviceUser::class, []);
// test
$handler = new NewsFormHandler($newsManager, $user);
$newsReturned = $handler->handle($form, $request, NewsFormHandler::ADD);
// assert
$this->assertNull($newsReturned);
}
}
You can probably extract body of testShouldHandleASuccessfulFormSubmissionForAddANews and testShouldHandleASuccessfulFormSubmissionForEditANews to other method with parameter like $action = 'add'|'edit' (or use your defined contants NewsFormHandler::EDIT etc), as they're almost the same.
You can extract mock creation from above methods to a single parametrized method, as the process is almost the same (pass the differences as method arguments and let it do the dirty work).
You can also add some readability by using BDD style, as in example in page http://codeception.com/docs/05-UnitTests#BDD-Specification-Testing
i have problem with HWIOAuthBundle and google authentication, i can't complete work on OAuthProvider. After flush data, i want return entity object, that i saw example somewhere in stackoverflow.
But when i return $obj;
I catch error :
Catchable Fatal Error: Argument 2 passed to HWI\Bundle\OAuthBundle\Security\Core\Authentication\Token\OAuthToken::__construct() must be of the type array, integer given, called in /var/www/integra/vendor/hwi/oauth-bundle/Security/Core/Authentication/Provider/OAuthProvider.php on line 109 and defined
Construct this class :
public function __construct($accessToken, array $roles = array())
{
parent::__construct($roles);
$this->setRawToken($accessToken);
parent::setAuthenticated(count($roles) > 0);
}
Then i return:
return new JsonResponse(['accessToken' => $user->getToken(), 'Roles' => $user->getRoles()]); // I catch error what it loadUserByOAuthUserResponse() must return a UserInterface
class OAuthProvider extends OAuthUserProvider
{
protected $container, $em;
public function __construct(\Doctrine\ORM\EntityManager $em, $container)
{
$this->container = $container;
$this->em = $em;
}
public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$email = $response->getEmail();
if ($email === null) {
throw new NotFoundHttpException("User email adress not found", 404);
}
$name = $response->getFirstName();
$surname = $response->getLastName();
$photo = $response->getProfilePicture();
$repository = $this->em->getRepository('IdamasBillingBundle:User');
$user = $repository->searchByNameSurnameEmail($email);
if($user){
$login = new User();
$login->setEmail($email);
$session = $this->container->get('session');
$session->set('login', $login);
return $user;
} else {
$user = new User();
$user->setEmail($email);
$user->setName($name);
$user->setSurname($surname);
$user->setPosition('Just user');
$user->setRoles(1);
$user->setPhoto($photo);
$this->em->persist($user);
$this->em->flush();
$session = $this->container->get('session');
$session->set('login', $user);
// return $user;f
return new JsonResponse(['accessToken' => $user->getToken(), 'Roles' => $user->getRoles()]);
}
//return new RedirectResponse("/billing");
}
}
How i can to do it, that redirect to complete login page?
User object should have roles property, and it must be an array:
class User {
protected $roles = [];
public function getRoles() {
return $this->roles;
}
public function addRole($role) {
$this->roles[] = $role;
}
}
I have created an annotation class called #Module, and a command GenerateModulesCommand. What I want is to find all controller actions that have the #Module annotation.
Example :
/**
*
* #Module(name='sidebar', enabled=true')
*/
public function sidebarAction($name) {
$ape = new ArrayParamsExtension ();
return $this->render('ModuleManagerBundle:Default:sidebar.html.twig', $ape->getArrayParams($name));
}
I want to be able to look at the specific properties in the #Module (name, enabled, etc...)
So far, this is my execute method from my Command :
protected function execute(InputInterface $input, OutputInterface $output) {
$path = $this->getApplication()->getKernel()->locateResource('#ModuleManagerBundle');
$driver = new PHPDriver($path);
$classes = $driver->getAllClassNames();
foreach ($classes as $key => $class) {
$reader = new AnnotationReader();
$annotationReader = new CachedReader(
$reader, new ArrayCache()
);
$reflClass = new ReflectionClass("\Controller\\" . $reportableClass);
$annotation = $annotationReader->getClassAnnotation(
$reflClass, 'Custom_Annotation'
);
if (is_null($annotation)) {
unset($classes[$key]);
}
}
$output->writeln($path);
}
I found this code on sof, but I don't know how to search all Controller classes and all the Actions inside them..
You can try this in your function
use Doctrine\Common\Annotations\AnnotationReader;
your function
public function getControllersWithAnnotationModules()
{
$allAnnotations = new AnnotationReader();
$controllers = array();
foreach ($this->container->get('router')->getRouteCollection()->all() as $route) {
$defaults = $route->getDefaults();
if (isset($defaults['_controller'])) {
$controllerAction = explode(':', $defaults['_controller']);
$controller = $controllerAction[0];
if (!isset($controllers[$controller]) && class_exists($controller)) {
$controllers[$controller] = $controller;
}
}
}
$controllersWithModules = array();
foreach($controllers as $controller){
$reflectionClass = new \ReflectionClass($controller);
$module = $allAnnotations->getClassAnnotation($reflectionClass,'Acme\YourBundle\Module');
if($module)
$controllersWithModules[] = $controller;
}
return $controllersWithModules ;
}
Here's my code:
$form = $this->createFormBuilder($signupAttempt)
->add('email', 'text', array("label" => "your email:"))
->add('password', 'password', array("label" => "your password:"))
->add('passwordRepeat', 'password', array("label" => "repeat password:"))
->getForm();
if ($request->isMethod('POST')) {
$form->bindRequest($request);
$attempt = $form->getData();
$this->changeSomeAttributesOfSignupAttempt($attempt); // this does not work
if ($form->isValid()) { // this is not taking into account the modification made inside changeSomeAttributesOfSignupAttempt
return new Response("data provided are valid - u signiged up!");
}
}
See my problem? I'd like to make some changes to the entity and expect the form to be aware of such changes. Unfortunately it looks like the changes that I make are not perceived and, as a result, the rules defined in validaition.xml for the class SignupAttempt are not fulfilled.
here's my validation.xml for the entity SignupAttempt:
<getter property="emailInUseAlready">
<constraint name="False">
<option name="message">signup_attempt.whole.email_in_use</option>
</constraint>
</getter>
and the entity class itself:
class SignupAttempt {
protected $id = null;
protected $email = null;
protected $password = null;
protected $passwordRepeat = null;
protected $emailInUseAlredy = true;
public function __construct($email = null, $password = null, $passwordReapeat = null) {
$this->email = $email;
$this->password = $password;
$this->passwordRepeat = $passwordReapeat;
}
public function getId() {
return $this->id;
}
public function setId($id) {
$this->id = $id;
}
public function getEmail() {
return $this->email;
}
public function setEmail($email) {
$this->email = $email;
}
public function getPassword() {
return $this->password;
}
public function setPassword($password) {
$this->password = $password;
}
public function getPasswordRepeat() {
return $this->passwordRepeat;
}
public function setPasswordRepeat($passwordRepeat) {
$this->passwordRepeat = $passwordRepeat;
}
public function setEmailInUseAlready($bool) {
$this->emailInUseAlredy = $bool;
}
public function isEmailInUseAlready() {
return $this->emailInUseAlredy;
}
public function isSecondPasswordMatching() {
return $this->password === $this->passwordRepeat;
}
public function import(array $data) {
throw new \RuntimeException("implement this");
}
}
any idea?
When one performs $form->isValid(), the returned (boolean) value is in fact pre-evaluated at the time when the request was bound to the form.
As a result, changing values of the entity returned by $form->getData() is totally useless as validation happens beforehand and on the initial values held by the entity object when it is originally created.
Here is my problem.
I am curently learning Symfony and I have created a form with a formType file and a formHandler.
I'd like now to use values of the form in my handler but I can't figure how to call those values, which method can I use? I've tried many method of the request class but it doesn't work.
Could you help me please?
Here is my handler. Some of my try are still in it commented, it's quiet simple, I'm just trying to do an echo.
class adminFormHandler
{
protected $form;
protected $request;
protected $em;
public function __construct(Form $form, Request $request, EntityManager $em)
{
$this->form = $form;
$this->request = $request;
$this->em = $em;
}
public function process()
{
if( $this->request->getMethod() == 'POST' )
{
$this->form->bindRequest($this->request);
//if( $this->form->isValid() )
//{
//echo $this->request->get('nom');
//$param = $this->request->request->keys();
//$param = $this->form->getData(nom);
//echo $param;
$myfield = $form->getAttribute('nom');
echo $myfield->getData();
//echo $param;//$this->form->get('nom')->getText();
//$this->onSuccess($this->form->getData());
return true;
//}
}
return false;
}
public function onSuccess1(/*Students $students*/)
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 1';
}
public function onSuccess2()
{
//$this->em->persist($students);
//$this->em->flush();
echo'on success 2';
}
}
You can use:
$data = $this->form->getData();
$myfield = $data['nom'];
or
$myfield = $this->form->get('nom')->getData();