Python 如何避免;ClientDirectError:检测到循环";测试烧瓶应用程序时出错(以及如何触发)?
环境:Python 如何避免;ClientDirectError:检测到循环";测试烧瓶应用程序时出错(以及如何触发)?,python,unit-testing,redirect,flask,flask-testing,Python,Unit Testing,Redirect,Flask,Flask Testing,环境: Python 3.6.1 烧瓶0.12.2 Werkzeug 0.14.1 在为我的应用程序编写测试时,我发现了以下特点:如果在Flask应用程序的测试中,您将“连续”两次重定向到同一urlClientDirectError:loop detected将被抛出,即使它在第二次重定向后停止重定向(即实际上没有发生循环) 考虑以下简化示例: app.py from flask import ( Flask, redirect, url_for, sess
- Python 3.6.1
- 烧瓶0.12.2
- Werkzeug 0.14.1
在为我的应用程序编写测试时,我发现了以下特点:如果在Flask应用程序的测试中,您将“连续”两次重定向到同一url
ClientDirectError:loop detected
将被抛出,即使它在第二次重定向后停止重定向(即实际上没有发生循环)
考虑以下简化示例:
app.py
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
if not session.get('test', False):
session['test'] = True
return redirect(url_for('index'))
else:
return "Hello"
@app.route('/redirection/')
def redirection():
# do something — login user, for example
return redirect(url_for('index'))
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/redirection/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
from unittest import TestCase
from isolated_app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
测试重定向.py
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
if not session.get('test', False):
session['test'] = True
return redirect(url_for('index'))
else:
return "Hello"
@app.route('/redirection/')
def redirection():
# do something — login user, for example
return redirect(url_for('index'))
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/redirection/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
from unittest import TestCase
from isolated_app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
现在,如果我运行测试,它将抛出一个clientredirectorror:loop detected
(尽管从代码中可以看出,第二次重定向只会发生一次)
如果我只是运行应用程序并转到/redirection/
,它会毫无问题地将我带到索引(即/
),并且不会发生循环
我之所以需要如果不是session.get('test',False):index()
中的,是因为在我的应用程序中,我使用它在会话中设置一些东西,以防用户第一次访问/
。正如代码中的注释所示,在我的“真实”应用程序中,redirection()
是一个让用户登录的函数
我的问题是:
是否有一种“正确”的方法来克服在类似情况下抛出ClientDirectError:loop detected
(即是否有可能使测试运行并通过)
是否有更好的/更正确的方法为“首次”用户设置会话中的内容
上述行为是否可以被视为中的错误(即实际循环未发生,但仍会抛出clientredirector:loop detected
)李>
解决方法,我提出了(仍然没有回答我的问题):
这可能看起来多余,但这只是一个简化的示例(如果将self.test\u client.get('/redirection/')
替换为类似self.test\u client.post('/login/',data=dict(username='user',password='pass'),可能会更有意义)
看来,我现在准备好了(张贴后几乎有1.5个酵母)发送至:
可以进行试运行并通过。
根据上述代码,问题末尾提供的变通方法可以解决问题,但可以缩短为:
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True) # navigating to '/', directly
self.assertTrue('Hello'.encode('ascii') in response.data)
在这种特殊情况下,不需要使用self.test\u client.get('/redirection/')
,行。
但是,如果对/redirection/
中的会话['test']
进行了一些更改,如下所示:
@app.route('/redirection/')
def redirection():
session['test'] = True
return redirect(url_for('index'))
然后,self.test\u client.get('/redirection/')
将是必要的,所以测试将变成:
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
self.test_client.get('/redirection/')
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
这就是所谓的“变通方法”,它只是防止测试连续两次重定向到/
(这正是导致ClientDirectError:loop detected
——请参阅下面第3点的答案)
是否有更好的方法-将取决于应用程序实现的确切细节。在问题中的示例中,索引中的重定向实际上是不必要的,可以删除:
@app.route('/')
def index():
session['test'] = session.get('test', True)
return "Hello"
顺便说一句,这样的改变也会使最初的测试(从问题)通过
据我所知,这种行为是“精心设计的”,即:ClientRedirectError:loop detected
,当重定向到同一url时(至少)连续发生两次。下面是一些示例
此测试不会遇到ClientDirectError
(因为重定向只发生一次):
独立应用程序py
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
if not session.get('test', False):
session['test'] = True
return redirect(url_for('index'))
else:
return "Hello"
@app.route('/redirection/')
def redirection():
# do something — login user, for example
return redirect(url_for('index'))
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/redirection/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
from unittest import TestCase
from isolated_app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
但是,如果应用程序的代码将更改为:
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
elif session['test'] < 2:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
如果我们尝试运行测试,这将打印12
,然后失败werkzeug.test.clientDirectError:loop detected
。另一方面,如果我们运行此应用程序并在FireFox中转到/
,浏览器将显示页面未正确重定向的消息,应用程序将打印12 3 4 5 6…21
,在控制台中
看来,我现在已经准备好(发布后差不多有1.5个酵母)去:
可以进行试运行并通过。
根据上述代码,问题末尾提供的变通方法可以解决问题,但可以缩短为:
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True) # navigating to '/', directly
self.assertTrue('Hello'.encode('ascii') in response.data)
在这种特殊情况下,不需要使用self.test\u client.get('/redirection/')
,行。
但是,如果对/redirection/
中的会话['test']
进行了一些更改,如下所示:
@app.route('/redirection/')
def redirection():
session['test'] = True
return redirect(url_for('index'))
然后,self.test\u client.get('/redirection/')
将是必要的,所以测试将变成:
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
self.test_client.get('/redirection/')
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
这就是所谓的“变通方法”,它只是防止测试连续两次重定向到/
(这正是导致ClientDirectError:loop detected
——请参阅下面第3点的答案)
是否有更好的方法-将取决于应用程序实现的确切细节。在问题中的示例中,索引中的重定向实际上是不必要的,可以删除:
@app.route('/')
def index():
session['test'] = session.get('test', True)
return "Hello"
顺便说一句,这样的改变也会使最初的测试(从问题)通过
据我所知,这种行为是“精心设计的”,即:ClientRedirectError:loop detected
,当重定向到同一url时(至少)连续发生两次。下面是一些示例
此测试不会遇到ClientDirectError
(因为重定向只发生一次):
独立应用程序py
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
if not session.get('test', False):
session['test'] = True
return redirect(url_for('index'))
else:
return "Hello"
@app.route('/redirection/')
def redirection():
# do something — login user, for example
return redirect(url_for('index'))
from unittest import TestCase
from app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/redirection/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
from unittest import TestCase
from isolated_app import app
class RedirectTestCase(TestCase):
def setUp(self):
self.test_client = app.test_client()
def testLoop(self):
response = self.test_client.get('/', follow_redirects=True)
self.assertTrue('Hello'.encode('ascii') in response.data)
但是,如果应用程序的代码将更改为:
from flask import (
Flask,
redirect,
url_for,
session
)
app = Flask(__name__)
app.secret_key = 'improper secret key'
@app.route('/')
def index():
session['test'] = session.get('test', 0)
if session['test'] < 1:
session['test'] += 1
return redirect(url_for('index'))
elif session['test'] < 2:
session['test'] += 1
return redirect(url_for('index'))
else:
return "Hello"
这将打印12
,然后以werkzeug.test.clientDirectError失败:检测到循环
,如果我们愿意的话