簡體   English   中英

如何使用sqlalchemy和sqlite測試mysql查詢?

[英]How to test mysql queries using sqlalchemy and sqlite?

我有以下用Python3.6編寫的代碼結構,我需要使用sqlite3進行測試(由於我的項目中定義了標准):

class BigSecretService:
    """ Class designed to make calculations based on data stored in MySQL. """
    def load_data(self):
        # load some data using sqlalchemy ORM

    def get_values_from_fields(self, fields):
        # here's getting values via sqlalchemy execute with raw query:
        self.sql_service.execute(SOME_QUERY)

    def process_data(self, data, values):
        # again execute some raw query
        # process data and put into result list
        return reuslt_list

    def make_calculations(self, params):
        data = self.load_data()
        values = self.get_values_from_fields(fields)
        result_vector = process_data(data, values)

SOME_QUERY在單獨的模塊中,其格式如下所示:

"SELECT SUM(some_field) FROM some_table WHERE col1 = :col1 AND col2 = :col2"

為了在我的組件測試中介紹make_calculations,我設計了一些糟糕的補丁:

class PatchedConnection:                                                                                                   
""" Class is used to transform queries to sqlite format before executing. """                                          
def __init__(self, connection, engine):                                                                                
    self.connection = connection                                                                                       
    self.engine = engine                                                                                               

def __call__(self):                                                                                                    
    conn = self.connection()                                                                                           
    conn.execute = self.patched_execute(conn.execute)                                                                  
    return conn                                                                                                        

def transform_date(self, date):                                                                                        
    try:                                                                                                               
        # quick check just for testing                                                                                 
        if '+00:00' in date:                                                                                           
            date = date.replace('T', ' ').replace('+00:00', '.000000')                                                 
    finally:                                                                                                           
        return date                                                                                                    

def patched_execute(self, f_execute):                                                                                  
    def prepare_args_for_sqlite(query, *args):                                                                         
        # check if query is in sqlite format                                                                           
        if args:                                                                                                       
            if '?' in str(query):                                                                                      
                args = list(map(self.transform_date, list(args[0].values())))                                          
                return self.engine.execute(str(query), args)                                                           
            return f_execute(query, args[0])                                                                           
        else:                                                                                                          
            return f_execute(query)                                                                                    
    return prepare_args_for_sqlite

然后在測試中看起來像這樣:

   QUERY_TEMPLATE_SQLITE = 'SELECT SUM(some_field) FROM some_table WHERE col1 = ? AND col2 = ?'
   with mock.patch('path_to_my_service.SOME_QUERY', QUERY_TEMPLATE_SQLITE):           
      self.sql_service.get_connection = PatchedConnection(self.sql_service.get_connection, self.engine)               
      response = self.client.simulate_post("/v1/secret_service/make_calculations",                      
                                           headers=self.auth_header,                                          
                                           body=json.dumps(payload))                                          

      self.assertEqual(response.status_code, 200)    
      # then check response.text

到目前為止,它仍然有效,但是我相信必須有更好的解決方案。 而且,在dict中的patched_execute參數中,args被轉換為list,誰知道dict值的順序是否始終相同。 因此,我的問題是如何使用給定的工具以正確的方式執行此類測試?

如果您需要攔截和處理發送到數據庫的SQL,則使用核心事件https://docs.sqlalchemy.org/en/13/core/events.html將是最簡單的方法。 如SQLAlchemy文檔的以下示例中所述, before_cursor_execute事件將滿足您的目的。

@event.listens_for(engine, "before_cursor_execute", retval=True)
def before_cursor_execute(conn, cursor, statement, parameters, context, executemany):
    # do something with statement, parameters
    return statement, parameters

但是,從您給出的示例中,我不確定是否有必要這樣做。 您列出的MySQL查詢也是有效的SQLite查詢,不需要任何操作。 同樣,如果您將參數作為python對象而不是字符串進行傳遞,則同樣無需進行任何操作,因為SQLAlchemy會將其正確映射到后端。

暫無
暫無

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

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