2015-08-29 44 views
5

我想添加单元测试到我的烧瓶应用程序,测试有效和无效登录+注册表单行为。目前,我有一个登录表单和一个登录表单,托管在一个页面和路由中,并使用隐藏的输入字段来标识提交的两个表单中的哪一个/确定下一个操作。如何在路由上有多个表单时单元测试表单提交?

我的问题是 - 我该如何编写一个针对页面上特定表单的单元测试?到目前为止,我所见过的所有例子都将数据发布到特定的路线,这是我目前正在做的。但那是失败的,因为我需要一个额外的方式来说“我们正在提交x表单”。

那么有没有办法在发布请求中添加“并且我们正在提交x表单”呢?

** 编辑添加,这里是我尝试传递隐藏的表单数据在数据字典中的不同方式,但没有成功。

data = dict(username="[email protected]", password="test", login_form) 
data = dict(username="[email protected]", password="test", "login_form") 
data = dict(username="[email protected]", password="test", login_form=True) 

登录单元测试:在views.py

from app import app 
import unittest 

class FlaskTestCase(unittest.TestCase): 

    #ensure that login works with correct credentials 
    def test_correct_login(self): 
    tester = app.test_client(self) 
    response = tester.post(
     '/login', 
     data = dict(username="[email protected]", password="test"), 
     follow_redirects=True 
    ) 
    self.assertIn(b'you are logged in', response.data) 

登录路由:

@app.route('/login', methods=['POST', 'GET']) 
def login(): 
    login_form = LoginForm() 
    signup_form = SignupForm() 
    error_login = '' 
    error_signup = '' 

    #login form 
    if 'login_form' in request.form and login_form.validate(): 
    # do login form stuff 

    #signup form 
    if 'signup_form' in request.form and signup_form.validate(): 
    # do signup form stuff 

    return render_template('login.html', login_form=login_form, signup_form=signup_form, error=error) 

的login.html:

<div class="login-form form-400"> 
     <h3>Log In To Your Account</h3> 
     <form action="" method="post"> 
     <input type="hidden" name="login_form"> 
     {% if error_login != '' %} 
     <label class="error"> 
     {{ error_login }} 
     </label> 
     {% endif %} 

     {% from "_formhelper.html" import render_field %} 
     {{ login_form.hidden_tag() }} 
     {{ render_field(login_form.email, placeholder="Your Email", class="form-item__full", type="email") }} 
     {{ render_field(login_form.password, placeholder="Your Password", class="form-item__full") }} 
     <input type="submit" value="Login" class="button button-blue"> 
    </form> 
    </div> 

    <p class="login-divider">or</p> 

    <div class="signup-form form-400"> 
    <h3>Create a New Account</h3> 
    <form action="" method="post"> 
     <input type="hidden" name="signup_form"> 
     {% if error_signup != '' %} 
     <label class="error"> 
     {{ error_signup | safe}} 
     </label> 
     {% endif %} 

     {% from "_formhelper.html" import render_field %} 
     {{ signup_form.hidden_tag() }} 
     {{ render_field(signup_form.username, placeholder="Pick a Username", class="form-item__full") }} 
     {{ render_field(signup_form.email, placeholder="Your Email", class="form-item__full", type="email") }} 
     {{ render_field(signup_form.password, placeholder="Create a Password", class="form-item__full") }} 

     <input type="submit" value="Sign Up" class="button button-green"> 
    </form> 
    </div> 
+0

您需要执行以下两项操作之一。要么你需要在表单中包含一个具有唯一名称或值的输入,或者我推荐的方式,每个表单都应该发布到它自己的端点。 – dirn

回答

1

更新: 感谢您使用已经尝试过的方式更新您的问题!关于导致此问题的原因,我还有其他一些想法。

让我们继续看看HTML,并试图了解你的程序建立在其上的技术。在服务器端的login.html文件,注意到这些行:

 {% from "_formhelper.html" import render_field %} 
     {{ login_form.hidden_tag() }} 
     {{ render_field(login_form.email, placeholder="Your Email", class="form-item__full", type="email") }} 
     {{ render_field(login_form.password, placeholder="Your Password", class="form-item__full") }} 

它不是HTML,并可能正在在服务器端处理,以产生HTML和服务给客户。包含login_form.hidden_tag()的行看起来很有趣,所以我建议在浏览器中加载此页面并检查提供给客户端的HTML。不幸的是,我之前没有使用Flask,所以我不能再给予任何直接帮助。

但是,我的建议是继续深入研究Flask和HTML表单如何工作。关于Python的好处是你可以访问库的源代码,它可以让你弄清楚它们是如何工作的,这样你就可以学习如何使用它们并修复使用它们的应用程序中的错误。

对不起,我不能给你更直接的帮助,祝你好运!


让我们来看看的login.html。当您提交表单时,views.py中的登录路由如何知道提交了哪个表单?如果您了解HTML表单,嵌套在表单中的<input>元素将用于在此情况下将数据发布到您的服务器/应用程序。

返回登录。HTML,注意以下两行:

... 
     <h3>Log In To Your Account</h3> 
     <input type="hidden" name="login_form"> 
... 
    <h3>Create a New Account</h3> 
    <form action="" method="post"> 
     <input type="hidden" name="signup_form"> 
... 

那些是<input>元件,与一种类型的“隐藏”,所以它们将不显示,与被包括在“login_form”和“signup_form”,名称由表单提交的数据。

现在在views.py登录路线,你会发现有两行:

#login form 
    if 'login_form' in request.form and login_form.validate(): 
    # do login form stuff 

    #signup form 
    if 'signup_form' in request.form and signup_form.validate(): 
    # do signup form stuff 

那些正在测试,看是否短语“login_form”或“signup_form”是出现在名单request.form。回到现在,你的单元测试:

response = tester.post(
     '/login', 
     data = dict(username="[email protected]", password="test"), 
     follow_redirects=True 
    ) 

通知你传入dict,这是模仿形式的数据,所以你应该包括两种“login_form”或“signup_form”中的数据,以模仿的行为HTML表单正确。

如果您不熟悉HTML Forms和HTTP Post,我会建议您搜索一些教程,或者阅读MDN或其他地方的文档。当在技术(如HTTP和HTML)上构建软件时,在您遇到软件中的错误时了解这些技术的工作方式会很有帮助。

希望这可以帮助,让我知道,如果我可以澄清任何事情!

+1

感谢您的回复。我的问题是如何传递字典中的“login_form”数据。我尝试了一些东西,包括'data = dict(username =“[email protected]”,password =“test”,login_form)'和'data = dict(username =“[email protected]”,password =“ test“,”login_form“)和'data = dict(username =”[email protected]“,password =”test“,login_form = True)'没有成功。我会用这个信息更新我的问题。 – SeeEmBee

+0

@SeeEmBee感谢您的反馈,我用更多的建议更新了我的答案。对不起,我无法提供帮助! – drdrez

2

好吧,我想通了。要通过login_form信息,我不得不结束了对login_form传递一个空字符串是这样的:

def test_correct_login(self): 
    tester = app.test_client(self) 
    response = tester.post(
     '/login', 
     data = dict(username="[email protected]", password="test", login_form=""), 
     follow_redirects=True 
    ) 
    self.assertIn(b'you are logged in', response.data) 

我在我的views.py扔print request.form这条路,然后做这个看到了空字符串。

它仍然失败,但因为login_form.validate()由于WTForms模块添加了csrf标记而失败。最后,这个讨论有了答案。 Flask-WTF/WTForms with Unittest fails validation, but works without Unittest

感谢@ drdrez为您的建议!

0

您可能遇到问题,因为您尚未将请求标记为表单应用程序内容类型。我注意到你正在尝试访问request.form,它要求以某种方式解析数据包。您可以尝试执行以下操作:

response = tester.post(
    '/login', 
    data = dict(username="[email protected]", password="test"), 
    follow_redirects=True, 
    headers = {"Content-Type":"application/x-www-form-urlencoded"} 
)