在Selenium中测试身份验证UI

3 投票
1 回答
2358 浏览
提问于 2025-04-16 09:51

我正在用selenium和pylons来测试用户的操作。一切都很顺利,直到我开始测试一个需要登录的界面——就是输入用户名和密码的登录屏幕。问题是,Chrome浏览器(我在selenium中使用的浏览器)弹出了一个对话框,询问是否要保存这些登录信息。之后,所有的测试都失败了。

有没有人能给我一些关于如何在selenium中处理需要身份验证的界面,特别是那些可能弹出对话框的界面的建议?我知道有一个关于selenium的警告,提到“不要这样做,应该这样做”。如果有人能给我这样的建议,那就太好了。


项目中的文件路径如下:

project/tests/lib/selenium/login_page.py

"""
LoginPage represents the page where users are authenticated for the application
"""


class LoginPage(object):
    """This is the LoginPage class."""

    login = '/authentication/login'
    logout = '/authentication/logout'
    home = '/home'

    def __init__(self, browser):
        self._browser = browser

    def goto_login(self, baseurl):
        return self._browser.go_to(baseurl + self.login)

    def goto_logout(self, baseurl):
        return self._browser.go_to(baseurl + self.logout)

    def goto_home(self, baseurl):
        return self._browser.go_to(baseurl + self.home)

    def enter_credentials(self, username, password):
        element_by_id = self._browser.get_element_by_id
        element_by_id("login").value = username
        element_by_id("password").value = password

    def submit_form(self):
        element = self._browser.get_element_by_id('submit')
        return self._browser.click(element)

project/tests/selenium/test_login_page.py

"""Tests the login page."""

import nose.tools as nt
from nose.plugins.skip import SkipTest

from assess.tests.selenium import SeleniumTestBase
from assess.tests.lib.selenium.login_page import LoginPage


class TestLoginPage(SeleniumTestBase):
    """Tests the login page."""

    def _login_page(self):
        return self.baseurl + '/authentication/login'

    def setUp(self):
        nt.set_trace()
        super(TestLoginPage, self).setUp()
        self.page = LoginPage(self.browser)

    def tearDown(self):
        super(TestLoginPage, self).tearDown()
        self.page = None

    def test_login_page_fail(self):
        # Logout before beginning test
        self.page.goto_logout(self.baseurl)

        self.page.goto_login(self.baseurl)
        nt.assert_true(self.browser.get_url().startswith(self._login_page()))
        self.page.enter_credentials('foo', 'random')
        self.page.submit_form()

    def test_login_page_success(self):
        # Logout before beginning test
        self.page.goto_logout(self.baseurl)

        self.page.goto_login(self.baseurl)
        nt.assert_true(self.browser.get_url().startswith(self._login_page()))
        self.page.enter_credentials('user', 'good-password')
        self.page.submit_form()

project/templates/login.html.mako

<%inherit file="/layout.html.mako" />

${h.stylesheet_link('login.css')}

<form action="/__do_login" method="POST">
    <fieldset>
        <p>
        <label for="login">User name</label><br />
        <input id="login" name="login" type="text" maxlength="40" value="" />
        </p>
        <p>
        <label for="password">Password</label><br />
        <input id="password" name="password" type="password" maxlength="40" value="" />
        </p>
        <p class="submit">
        <input id="submit" type="submit" value="Submit" />
        </p>
    </fieldset>
</form>

etc/who.ini

[general]
request_classifier = repoze.who.classifiers:default_request_classifier
challenge_decider = repoze.who.classifiers:default_challenge_decider

[identifiers]
plugins = foo
          friendly_form;browser

[authenticators]
plugins = foo 

[challengers]
plugins = friendly_form;browser
          foo

[plugin:foo]
use = ...
host = ...
logout_path_regex = /authentication/logout
httponly = True

[plugin:friendly_form]
use = repoze.who.plugins.friendlyform:FriendlyFormPlugin
login_form_url = /authentication/login
login_handler_path = /__do_login
post_login_url = /home
logout_handler_path = /authentication/logout
post_logout_url = /authentication/login

project/config/routing.py

def make_map(config):
    """Create, configure and return the routes Mapper"""
    mapper = Mapper(directory=config['pylons.paths']['controllers'],
                 always_scan=config['debug'])
    mapper.minimization = False
    mapper.explicit = False

    # The ErrorController route (handles 404/500 error pages); it should
    # likely stay at the top, ensuring it can always be resolved
    mapper.connect('/error/{action}', controller='error')
    mapper.connect('/error/{action}/{sid}', controller='error')

    # CUSTOM ROUTES HERE

...
    mapper.connect('/authentication/login',
                   controller='authentication',
                   action='index')
    mapper.connect('/authentication/logout',
                   controller='authentication',
                   action='logout')

project/controllers/authentication.py

"""
This module contains the login controller.
"""

import logging

from pylons.controllers.util import redirect
from pylons import url, tmpl_context as c, request

from project.lib.base import BaseController
from project.lib.authorize import user_is_authenticated

logger = logging.getLogger(__name__)


class AuthenticationController(BaseController):
    """ This controller serves the login page."""
    template = '/login.html.mako'

    def index(self):
        return self.render(self.template)

    def validate(self):
        """ render a login page if we're not logged in """
        c.came_from = request.params.get("came_from", url("home"))

        # If we're already authenticated, redirect us to where we started.
        if user_is_authenticated():
            msg = "User is authenticated: redirecting to %s" % c.came_from
            logger.info(msg)
            redirect(c.came_from)

        msg = "User is not authenticated: rendering %s" % self.template
        logger.info(msg)
        return self.render(self.template)

project/lib/authorize.py

''' Helper functions for the authorization and authentication mechanisms. '''
from pylons import request
from decorator import decorator
from pylons.controllers.util import abort


def user_is_authenticated():
    """ Returns True if is authenticated, else returns False.
    """
    identity = request.environ.get('repoze.who.identity')
    return identity and 'xxx' in identity


@decorator
def authenticated(func, *args, **kwargs):
    """ Check if is authenticated.  If not authenticated, abort with
        401 status.
    """
    if not user_is_authenticated():
        abort(401, 'You are not authenticated')
    return func(*args, **kwargs)

1 个回答

1

理想情况下,你应该为你的测试使用一个配置文件,并在这个配置文件中设置为永远不询问是否保存凭据。不过,遗憾的是,在Selenium 1中无法指定一个自定义的Chrome配置文件,但在Selenium 1中可以为Firefox做到这一点,或者你可以升级到Selenium 2(WebDriver) - 更多信息请查看这个讨论串

撰写回答