如何在路线上的多个表格中对表单提交进行单元测试?

See*_*Bee 8 html python forms unit-testing flask

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

我的问题是 - 如何编写针对页面上特定表单的单元测试?到目前为止,我看到的所有示例都将数据发布到特定路径,这正是我正在做的事情.但这是失败的,因为我需要一种额外的方式来说"我们正在提交x形式".

那么有没有办法在帖子请求中添加"我们正在提交x表单"?

**编辑添加,以下是我试图在后期数据字典中传递隐藏表单数据的不同方法,但没有成功.

data = dict(username="test@gmail.com", password="test", login_form) 
data = dict(username="test@gmail.com", password="test", "login_form")
data = dict(username="test@gmail.com", password="test", login_form=True)
Run Code Online (Sandbox Code Playgroud)

登录单元测试:

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="test@gmail.com", password="test"),
      follow_redirects=True
      )
    self.assertIn(b'you are logged in', response.data)
Run Code Online (Sandbox Code Playgroud)

views.py中的登录路由:

@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)
Run Code Online (Sandbox Code Playgroud)

的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>
Run Code Online (Sandbox Code Playgroud)

See*_*Bee 5

好吧,我想通了。要传递登录表单信息,我必须最终在登录表单上传递一个空字符串,如下所示:

def test_correct_login(self):
    tester = app.test_client(self)
    response = tester.post(
      '/login',
      data = dict(username="test@gmail.com", password="test", login_form=""),
      follow_redirects=True
      )
    self.assertIn(b'you are logged in', response.data)
Run Code Online (Sandbox Code Playgroud)

我通过print request.form在该路线的views.py中添加一个来做到这一点,然后看到空字符串。

它仍然失败,但因为login_form.validate()WTForms 模块添加的 csrf 令牌而失败。最终,这次讨论有了答案。 Flask-WTF / WTForms 与 Unittest 验证失败,但无需 Unittest 即可工作

感谢@drdrez 的建议!


drd*_*rez 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") }}
Run Code Online (Sandbox Code Playgroud)

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

不过,我的建议是继续深入研究 Flask 和 HTML 表单的工作原理。Python 的好处是您可以访问库的源代码,这使您可以了解它们的工作原理,以便您可以学习如何使用它们并修复使用它们的应用程序中的错误。

抱歉无法给您更直接的帮助,祝您好运!


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

回到login.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">
...
Run Code Online (Sandbox Code Playgroud)

这些<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
Run Code Online (Sandbox Code Playgroud)

这些正在测试列表中是否存在短语“login_form”或“signup_form” request.form。现在回到你的单元测试:

    response = tester.post(
      '/login',
      data = dict(username="test@gmail.com", password="test"),
      follow_redirects=True
      )
Run Code Online (Sandbox Code Playgroud)

请注意您在 中传递的数据dict,这是模仿表单数据,因此您可能应该包含“login_form”或“signup_form”以正确模仿 HTML 表单的行为。

如果您不熟悉 HTML 表单和 HTTP Post,我建议您搜索一些教程,或者只是阅读MDN或其他地方的文档。当基于某种技术(如 HTTP 和 HTML)构建软件时,当您在自己的软件中遇到错误时,了解这些技术的工作原理会很有帮助。

希望这有帮助,如果我可以澄清任何事情,请告诉我!