flask是个轻量级的python框架,特别适合写一个没有UI的web接口应用,并且提供了很友好的测试框架,参考链接http://flask.pocoo.org/docs/testing/,官方提供的测试范例实际上算是集成测试了,如果不想让测试依赖外部环境(比如数据库)怎么办呢?Mock!,推荐使用mockito-python,Mockito的Java版本就非常好用,python也同样给力,下载地址 http://code.google.com/p/mockito-python/ 。废话少说,来次TDD的体验吧。
先写个测试:
class LoginTest(unittest.TestCase):
def setUp(self):
self.db = mock()
self.app = myapp.create_app(self.db).test_client()
def tearDown(self):
unstub()
增加一个Post请求,用来进行登录。
def test_login(self):
rv = self.app.post('/login', data=dict(username='archie', password='mypassword'))
self.assertEqual(200, rv.status_code)
self.assertEqual('Login Successful!', rv.data)
当然,这个测试运行肯定会失败。
[wenwen@Archie flaskdemo]$ nosetests
E
======================================================================
ERROR: Failure: ImportError (No module named flaskdemo)
----------------------------------------------------------------------
Traceback (most recent call last):
......
File "/Users/wenwen/Documents/workspace/flaskdemo/flaskdemo_test.py", line 7, in <module>
import flaskdemo
ImportError: No module named flaskdemo
----------------------------------------------------------------------
Ran 1 test in 0.074s
FAILED (errors=1)
先让测试通过吧,写个flaskdemo.py。
from flask.app import Flask
def create_app(db):
# application
app = Flask(__name__)
app.config.from_object(__name__)
@app.route("/login", methods=["POST"])
def login():
return "Login Successful!"
return app
毫无悬念,测试通过了。但是我们还没写验证的逻辑呢,我们使用auth.py这个module里的verify这个方法来验证,这里不想牵扯到db访问的细节,也不想在运行测试的时候启动数据库,让Mock来吧,修改测试。
def test_login(self):
when(flaskdemo.auth).verify(self.db, "archie", "mypassword").thenReturn(True)
rv = self.app.post('/login', data=dict(username='archie', password='mypassword'))
verify(flaskdemo.auth).verify(self.db, "archie", "mypassword")
self.assertEqual(200, rv.status_code)
self.assertEqual('Login Successful!', rv.data)
测试失败了,写个auth.py,有个空方法就可以了,以后再实现,然后把它import到flaskdemo中,并调用。
@app.route("/login", methods=["POST"])
def login():
return "Login Successful!" if auth.verify(db, request.form.get("username"), request.form.get("password")) else "Login Failed!"
ok!测试通过了。
[wenwen@Archie flaskdemo]$ nosetests
.
----------------------------------------------------------------------
Ran 1 test in 0.103s
OK
不需要启动数据库,甚至不需要写验证逻辑。同理,当依赖的复杂逻辑在另外的module中时,就可以通过mock来解耦,方便进行单元测试。