BARNOWL
BARNOWL

Reputation: 3589

Error: Cannot instantiate interface symfony when unit testing

I'm trying to do a unit test for a signup method and im following this guide. I'm fairly new to unit testing.

i keep getting

1) App\Tests\Controller\SignUpControllerTest::testSignUp Error: Cannot instantiate interface Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface

/Applications/MAMP/htdocs/my_project/tests/Controller/SignUpControllerTest.php:19

I just don't think im doing this unit test right. Here is what i have. I'm not sure on what im doing. All i want to do is test the signup method.

UserController.php

public function signup(Request $request, UserPasswordEncoderInterface $passwordEncoder )
{
    $user = new User();

    $entityManager = $this->getDoctrine()->getManager();

    $user->setEmail($request->get('email'));
    $user->setPlainPassword($request->get('password'));
    $user->setUsername($request->get('username'));
    $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
    $user->setPassword($password);

    $entityManager->persist($user);
    $entityManager->flush();

    return $this->redirectToRoute('login');



}

SignUpControllerTest.php

namespace App\Tests\Controller;

use App\Entity\Product;
use App\Controller\UserController;
use App\Entity\User;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ObjectRepository;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class SignUpControllerTest extends WebTestCase
{

    public function testSignUp()
    {   
        $passwordEncoder = new UserPasswordEncoderInterface();
        $user = new User();
        $user->setEmail('[email protected]');
        $user->setPlainPassword('owlhunter');
        $user->setUsername('BarnMan');
        $password = $passwordEncoder->encodePassword($user, $user->getPlainPassword());
        $user->setPassword($password);

        $userRepository = $this->createMock(ObjectRepository::class);
        $userRepository->expects($this->any())
            ->method('find')
            ->willReturn($user);


        $objectManager = $this->createMock(ObjectManager::class);
        // use getMock() on PHPUnit 5.3 or below
        // $objectManager = $this->getMock(ObjectManager::class);
        $objectManager->expects($this->any())
            ->method('getRepository')
            ->willReturn($userRepository);

        $userController = new UserController($objectManager);
        $this->assertEquals(2100, $userController->signupTest());

    }


}

Upvotes: 2

Views: 4981

Answers (2)

Hassan Elshazly Eida
Hassan Elshazly Eida

Reputation: 849

WebTestCase :

Application tests are PHP files that typically live in the tests/Controller/ directory of your application it tell Symfony that we need the tools necessary to talk to our application as if we were doing so via HTTP.

KernelTest

use for to fetch a service from the dependency injection container it help you creating and booting the kernel in your tests

that's why I recommend you to use KernelTestCase

use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;

class SignUpControllerTest extends KernelTestCase
{
private $passwordEncoder;

protected function testSignUp(): void
{
   self::bootKernel();
    $this->passwordEncoder= self::getContainer()->get('Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface');
}

public function addShoes3()
{
     $passwordEncoder = $this->passwordEncoder;
    //continue
}
}

Upvotes: -1

The error is very clear. In the first line of your testSignUp method, you are creating an instance out of an interface, which cannot be done in PHP.

To create a usable object out of an interface in unit testing, create a mock object of it. Read PHP unit docs for that.

Upvotes: 2

Related Questions