重构功能,设计坚固

时间:2018-12-19 06:25:16

标签: python refactoring

我在这里有一个简单的应用示例:

说我有这段代码,可以处理用户请求以获取存储在数据库中的书籍清单。

from .handlers import all_books

@apps.route('/show/all', methods=['GET'])
@jwt_required
def show_books():
    user_name = get_jwt_identity()['user_name']
    all_books(user_name=user_name)

handlers.py中,我有:

def all_books(user_name):
        db = get_db('books')
        books = []
        for book in db.books.find():
            books.append(book)
        return books

但是在编写单元测试时,我意识到如果我在get_db()中使用all_books(),则很难对方法进行单元测试。 所以我认为这是个好方法。

from .handlers import all_books

@apps.route('/show/all', methods=['GET'])
@jwt_required
def show_books():
    user_name = get_jwt_identity()['user_name']
    db = get_db('books')
    collection = db.books
    all_books(collection=collection)

def all_books(collection):
        books = []
        for book in collection.find():
            books.append(book)
        return books

我想知道什么是好的设计? 让所有代码都在一个地方做一件事情,如第一个示例或第二个示例一样。

对我来说,第一个似乎更清晰,因为它把所有相关的逻辑都放在一个地方。但是在第二种情况下更容易通过伪造的集合进行单元测试。

1 个答案:

答案 0 :(得分:1)

您可能应该使用模拟库,请参见:https://docs.python.org/3/library/unittest.mock.html#quick-guide

(如果您使用python2,则需要pip install mock

def test_it():
    from unittest.mock import Mock,patch
    with patch.object(get_db,'function',Mock(return_value=Mock(books=[1,2,3]))) as mocked_db:
         x = get_db("ASDASD")
         console.log(x.books) 
         # you can also do cool stuff like this
         assert mocked_db.calledwith("ASDASD")

对于您来说很粗糙,您将必须构造稍微复杂一点的对象

my_mocked_get_db = Mock(return_value=Mock(books=Mock(find=[1,2,3,4])))
with patch.object(get_db,'function',my_mocked_get_db) as mocked_db:
         x = get_db("ASDASD")
         print(x.books.find())