dpx86402
dpx86402
2015-02-11 10:22

Symfony:测试自定义用户登录

已采纳

Just recently I got into testing pieces of a symfony application... For starters, I thought I would try and test a login form that should grant access to a private area.

The users for this private area are correctly persisted to the database and have been tried on the development enviroment. The config_test.yml file goes like this:

imports:
    - { resource: config_dev.yml }

framework:
    test: ~
    session:
        storage_id: session.storage.mock_file
    profiler:
        collect: false

web_profiler:
    toolbar: false
    intercept_redirects: false

swiftmailer:
    disable_delivery: true 

So it should use the database configuration exposed in config_dev.yml.

There's nothing special about my user provider:

providers:
    users:
        entity: 
            class: MyBundle:User
            property: login

As requested in the comments section, here's the security info. Please note that all namespaces, class names and relevant data have been changed, as I can't publish the real thing. If you spot any mistake it must have been me changing the relevant code.

security:
    encoders:
        MyBundle\Entity\User:
           algorithm: bcrypt
           cost: 12

    role_hierarchy:
        ROLE_CUSER:       ROLE_USER
        ROLE_CUSER_A: ROLE_CUSER
        ROLE_CUSER_B: ROLE_CUSER
        ROLE_CUSER_C: ROLE_CUSER
        ROLE_CUSER_D: ROLE_CUSER
        ROLE_CUSER_E: ROLE_CUSER

    providers:
        users:
            entity: 
                class: MyBundle:User
                property: login

    firewalls:
        dev:
            pattern:  ^/(_(profiler|wdt)|css|images|js)/
            security: false

        user_tools_login_firewall:
             pattern:   ^/user_tools/login$
             anonymous: ~
        user_tools:
             pattern: ^/user_tools
             http_basic: ~
             provider: users
             form_login:
                 login_path: /user_tools/login
                 check_path: /user_tools/login_check
             logout:
                 path: /user_tools/logout
                 target: /user_tools/home
                 invalidate_session: false

    access_control:
        - {path: /user_tools/login, roles: IS_AUTHENTICATED_ANONYMOUSLY}
        - {path: ^/user_tools/users/, roles: ROLE_CUSER_A}
        - {path: ^/user_tools/news/, roles: ROLE_CUSER_B}

Let's take a look at the testing unit...

class SecurityControllerTest extends WebTestCase
{
    const LOGIN_ERROR='this_is_a_non_existing_user';
    const PASS_ERROR='with_a_non_existing_pass';

    const LOGIN='this_is_a_valid_user';
    const PASS='with_a_valid_pass';
    const PASS_CRYPT='##and_this_is_the_encripted_pass_as_pasted_from_the_database##';

    const ID_SUBMIT='btn_submit';

    private $client;
    private $crawler;

    public function testIndex()
    {
        $this->client=static::createClient();
        $this->crawler=$this->client->request('GET', '/route_to_login');

        //Let's check that there are users in the database...
            $em=$this->client->getContainer()->get('doctrine')->getManager();
        $users=$em->getRepository("MyBundle:User")->findAll();
        $this->assertGreaterThan(0, count($users));

        //Now let's check that there's a valid user...
        $valid_user=$em->getRepository("MyBundle:User")->findBy(
            array('login' => self::LOGIN,
                'pass' => self::PASS_CRYPT));
        $this->assertGreaterThan(0, count($valid_user));

        //Let's check that there is no invalid user ;).
        $invalid_user=$em->getRepository("MyBundle:User")->findBy(
            array('login' => self::LOGIN_ERROR,
                'pass' => self::PASS_ERROR));
        $this->assertEquals(0, count($invalid_user));

        //The view should be the one I expect...
        $this->assertEquals('MyBundle\Controller\User\SecurityController::loginAction', $this->client->getRequest()->attributes->get('_controller'));

        //Let's try an invalid access...
        $this->form_login(self::LOGIN_ERROR, self::PASS_ERROR);
        $this->assertEquals('MyBundle\Controller\User\SecurityController::loginAction', $this->client->getRequest()->attributes->get('_controller'));

        //And now, let's try the good one!.
        self::form_login(self::LOGIN, self::PASS);
        $this->assertEquals('MyBundle\Controller\User\HomeController::homeAction', $this->client->getRequest()->attributes->get('_controller'));
    }

    private function form_login($login, $pass)
    {
        $form=$this->crawler->selectButton(self::ID_SUBMIT)->form();
        $form['_username']=$login;
        $form['_password']=$pass;
        $this->client->submit($form);
        $this->crawler=$this->client->followRedirect();
    }
}

The thing is, all tests are passed except the last one (that is, the good login). It does not go to the expected controller, but back to the login.

Here's the phpunit error:

There was 1 failure:

1) MyBundle\Tests\Controller\User\SecurityControllerTest::testIndex
Failed asserting that null matches expected 'MyBundle\Controller\User\HomeController::homeAction'.

Is there something I am missing here?. Everything is working as expected into the dev enviroment. Users do exists (and are asserted, as you can see). I am prepared to give more info as requested.

Thanks!.

  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享
  • 邀请回答

1条回答

  • duanrebo3559 duanrebo3559 6年前

    You forgot to define the default_target_path in your form_login configuration, try to add your path like this:

             form_login:
                 login_path: /user_tools/login
                 check_path: /user_tools/login_check
                 default_target_path: your_target_path
    
    点赞 评论 复制链接分享