2014-10-04 75 views
1

我正在通过模仿The Flask Mega-Tutorial来编写Web应用程序。Flask-SQLALchemy单元测试问题

正如我试图添加一些单元测试用例到我的代码。我发现教程中的测试用例有许多重复的代码。

这里是代码段:

def test_avatar(self): 
    u = User(nickname='john', email='[email protected]') 
    avatar = u.avatar(128) 
    expected = 'http://www.gravatar.com/avatar/d4c74594d841139328695756648b6bd6' 
    ... 

def test_make_unique_nickname(self): 
    u = User(nickname='john', email='[email protected]') 
    db.session.add(u) 
    db.session.commit() 
    ... 

的问题是,我想测试一个新的情况下,我每次都要重复这个过程:

u = User(nickname='john', email='[email protected]') 
db.session.add(u) 
db.session.commit() 

所以,我搬到这个过程如下所示:

import unittest 

from config import basedir 
from app import app, db 
from app.models import User 

u = User(nickname='john', email='[email protected]') # I put this out because some cases may want to use this stuff. 

def _init_database(): 
    db.session.add(u) 
    db.session.commit(u) 

class TestCase(unittest.TestCase): 
    def setUp(self): 
     app.config['TESTING'] = True 
     app.config['WTF_CSRF_ENABLED'] = False 
     app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:') 
     self.app = app.test_client() 
     db.create_all() 
     _init_database() # init database every time 

    def tearDown(self): 
     db.session.remove() 
     db.drop_all() 

    def test_case_1(self): 
     self.assertTrue(User.query.count() == 1) # case 1 

    def test_case_2(self): 
     self.assertTrue(User.query.count() == 1) # case 1 

if __name__ == '__main__': 
    unittest.main() 

正如你所看到的,两个测试用例是相同的。但是,只有一种情况可以通过。另一个将失败

但是,如果我移动到u = User(nickname='john', email='[email protected]')_init_database()

def _init_database(): 
    u = User(nickname='john', email='[email protected]') 
    db.session.add(u) 
    db.session.commit(u) 

现在每一件事情是好的。

我真的不知道为什么!你可以帮帮我吗?

回答

0

User实例是由ORM控制的对象,所以将其作为全局变量并不是一个好主意。该对象不仅包含您的数据,还包含数据库信息。通过使其成为全局数据库,您首先在数据库中使用它进行第一次测试,然后在数据库中使用它进行第二次测试。

一个更好的方法是创建一个新的User实例为每个测试,并在setUp()方法返回它:

def _init_database(): 
    u = User(nickname='john', email='[email protected]') 
    db.session.add(u) 
    db.session.commit() 
    return u 

然后你就可以该用户连接到你的测试用例,并从你的测试访问它。

+0

你的意思是我不应该使用全局变量。但是,如果我想使用多个用户呢?那么,我必须像这样返回(u1,u2,u3)'?我只能想办法解决它。只需制作所有这些用户对象变量。但是,每次我想要使用用户时,都必须使用像这样的'self.u1',这有点难看。 – 2014-10-06 13:11:51

+1

我并没有试图向你传达如何糟糕的全局变量,不好意思,如果它似乎这样。全局变量有时是有用的,但在这种情况下是有问题的,因为用户模型有点神奇,因为它们存储由SQLAlchemy控制的数据库元数据。我会在'TestCase'类中使'_init_database()'函数成为一个方法,并将所有用户存储为对象变量。然后创建一个'_get_users()'方法,返回你的三个用户,并在测试开始时将其称为'u1,u2,u3 = self._get_users()',这样就不必使用'self'。 u1'。 – Miguel 2014-10-06 16:43:32