簡體   English   中英

Flask 單元測試——模擬 Aerospike DB

[英]Flask unit tests -- mocking up Aerospike DB

我有以下端點,

    @developer_blueprint.route("/init_db", methods=["POST"])
    def initialize_database():
       try:
          upload_data(current_app)
          logger.debug("Database entries upload.")
          return jsonify({"result": "Database entries uploaded."}), 201
       except Exception as e:
          return jsonify({"error": str(e)})

    def upload_data(app):
       with open("src/core/data/data.json") as data_file:
          data = json.load(data_file)
          try:
             current_app.db.put(("somenamespace", "test", "default"), data, None)
          except Exception as e:
             raise e

我試圖弄清楚如何對此進行單元測試(我們需要覆蓋我們的代碼)。 我只是模擬 app.db 嗎? 我怎樣才能做到這一點?

任何建議,將不勝感激。

使用諸如unittest.mock 之類的東西模擬數據庫調用進行單元測試,然后在容器或 VM 中運行 Aerospike 進行端到端測試並不少見。

但是,請記住,Aerospike Python 客戶端庫是用 C 編寫的以獲得更好的性能,因此進行部分修補(又名“猴子修補”)並不容易。 例如,如果您嘗試簡單地修補aerospike.Client.put ,則會收到TypeError: can't set attributes of built-in/extension type

一種方法是創建一個模擬客戶端對象來替換 Aerospike 客戶端對象或對其進行子類化。 這個模擬對象的實現取決於你的代碼和你正在測試的案例。

以下面的示例代碼為例,其中app.db是 Aerospike 客戶端庫的一個實例:

# example.py
import aerospike
import json

class App(object):
    db = None
    def __init__(self):
        config = {'hosts': [('127.0.0.1', 3000)]}
        self.db = aerospike.client(config).connect()

def upload_data(app):
    with open("data.json") as data_file:
        data = json.load(data_file)

    try:
        app.db.put(("ns1", "test", "default"), data, None)
    except Exception as e:
            raise e

if __name__ == "__main__":
    app = App()
    upload_data(app)

在為upload_data函數編寫單元測試時,讓我們假設您要測試成功案例,該案例確定意味着調用put方法並且沒有引發異常:

# test.py
from unittest import TestCase, main
from unittest.mock import PropertyMock, patch
from example import App, upload_data
from aerospike import Client, exception


class MockClient(Client):
    def __init__(self, *args, **kwargs):
        pass

    def put(self, *args, **kwargs):
        return 0


class ExampleTestCase(TestCase):
    def test_upload_data_success(self):
        with patch.object(App, 'db', new_callable=PropertyMock) as db_mock:
            db_mock.return_value = client = MockClient()
            app = App()
            with patch.object(client, 'put') as put_mock:
                upload_data(app)
                put_mock.assert_called()


if __name__ == '__main__':
    main()

test_upload_data_success方法App.db屬性修補與MockClient類代替aerospike.Client類。 MockClient實例的put方法也被修補,以便可以斷言在調用upload_data之后調用put方法。

要測試 Aerospike 客戶端引發的異常是否從upload_data函數重新引發,可以修改MockClient類以顯式引發異常:

# test.py
from unittest import TestCase, main
from unittest.mock import PropertyMock, patch
from example import App, upload_data
from aerospike import Client, exception


class MockClient(Client):
    def __init__(self, *args, **kwargs):
        self.put_err = None
        if 'put_err' in kwargs:
            self.put_err = kwargs['put_err']

    def put(self, *args, **kwargs):
        if self.put_err:
            raise self.put_err
        else:
            return 0


class ExampleTestCase(TestCase):
    def test_upload_data_success(self):
        with patch.object(App, 'db', new_callable=PropertyMock) as db_mock:
            db_mock.return_value = client = MockClient()
            app = App()
            with patch.object(client, 'put') as put_mock:
                upload_data(app)
                put_mock.assert_called()

    def test_upload_data_error(self):
        with patch.object(App, 'db', new_callable=PropertyMock) as db_mock:
            db_mock.return_value = MockClient(put_err=exception.AerospikeError)
            app = App()
            with self.assertRaises(exception.AerospikeError):
                upload_data(app)


if __name__ == '__main__':
    main()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM