嘲笑雪花连接

时间:2018-04-27 23:26:09

标签: pytest python-unittest python-unittest.mock snowflake

我在python中有一个SnowflakeApi类,它只是作为SnowflakeConnection类顶部的包装器。我的SnowflakeApi是

import logging
import os
from snowflake.connector import connect    

class SnowflakeApi(object):
    """
    Wrapper to handle snowflake connection
    """

    def __init__(self, account, warehouse, database, user, pwd):
        """
        Handles snowflake connection. Connection must be closed once it is no longer needed
        :param account:
        :param warehouse:
        :param database:
        """
        self.__acct = self._account_url(account)
        self.__wh = warehouse
        self.__db = database
        self.__connection = None
        self.__user = user
        self.__pwd = pwd

    def __create_connection(self):

        try:
            # set the proxy here
            conn = connect(
                account=self.__acct
                , user=self.__user
                , password=self.__pwd
                , warehouse=self.__wh
                , database=self.__db
            )
            return conn
        except:
            raise Exception(
                "Unable to connect to snowflake for user: '{0}', warehouse: '{1}', database: '{2}'".format(
                    self.__user, self.__wh, self.__db))


    def get_connection(self):
        """
        Gets a snowflake connection. If the connection has already been initialised it is returned
        otherwise a new connection is created
        :param credentials_func: method to get database credentials.
        :return:
        """
        try:
            if self.__connection is None:
                self.__connection = self.__create_connection()
            return self.__connection
        except:
            raise Exception("Unable to initalise Snowflake connection")

    def close_connection(self):
        """
        Closes snowflake connection.
        :return:
        """
        self.__connection.close()

SnowflakeApi的命名空间是connection.snowflake_connection.SnowflakeApi(即我在名为connections的文件夹中有snowflake_connection.py)

我想使用pytest和unittest.mock为这个类编写单元测试。问题是我想模拟'connect'以便返回MagicMock对象并且不进行数据库调用。到目前为止,我已经尝试过:

  1. monkeypatch.setattr(connections.snowflake_connection,“connect”,return_value =“”)
  2. 将原来的类改为导入雪花。然后我创建了一个模拟对象并使用了monkeypatch.setattr(snowflake_connection,“snowflake”,my_mock_snowflake)。这不起作用
  3. 简而言之,我尝试过其他一些东西,但没有任何效果。我想做的就是模拟雪花连接,因此不会进行实际的数据库调用。

4 个答案:

答案 0 :(得分:1)

使用存根和依赖注入

class SnowflakeApiStub(SnowflakeApi)
    def __init__(self):
        # bypass super constructor
        self.__connection = MagicMock()      

def test_some_func():
    stub = SnowflakeApiStub()
    mock_connection = stub.__connection
    mock_cursor = mock_connection.cursor.return_value
    expect = ...
    actual = some_func(api=stub)
    assert expect == actual
    assert mock_cursor.execute.called

你的考试

{{1}}

答案 1 :(得分:1)

使用unittest.mock并修补连接的示例:

from unittest import TestCase
from unittest.mock import patch
from connection.snowflake_connection import SnowflakeApi

class TestSnowFlakeApi(TestCase):

    @patch('connection.snowflake_connection.connect')
    def test_get_connection(self, mock_connect)
        api = SnowflakeApi('the_account', 
                           'the_warehouse', 
                           'the_database', 
                           'the_user', 
                           'the_pwd')

        api.get_connection()

        mock_connect.assert_called_once_with(account='account_url',  # Will be the output of self._account_url()
                                             user='the_user',
                                             password='the_pwd',
                                             warehouse='the_warehouse',
                                             database='the_database')

如果您正在测试使用SnowFlakeApi包装器的其他类,那么您应该使用相同的方法,但在这些测试中修补SnowFlakeApi本身。

from package.module.SomeClassThatUsesSnowFlakeApi

class TestSomeClassThatUsesSnowFlakeApi(TestCase):

    @patch('package.module.SnowFlakeApi')
    def test_some_func(self, mock_api):
        instance = SomeClassThatUsesSnowFlakeApi()
        instance.do_something()

        mock_api.assert_called_once_with(...)
        mock_api.return_value.get_connection.assert_called_once_with()

另请注意,如果您使用的是Python 2,则需要pip install mock然后from mock import patch

答案 2 :(得分:0)

这是我们使用snowflake connector, cursor and fetch_all模拟python mock and patch的另一种方式。

import mock
import unittest
from datetime import datetime, timedelta

import feed_daily_report


class TestFeedDailyReport(unittest.TestCase):
    @mock.patch('snowflake.connector.connect')
    def test_compare_partner(self, mock_snowflake_connector):
        tod = datetime.now()
        delta = timedelta(days=8)
        date_8_days_ago = tod - delta
        query_result = [('partner_1', date_8_days_ago)]
        mock_con = mock_snowflake_connector.return_value
        mock_cur = mock_con.cursor.return_value
        mock_cur.fetchall.return_value = query_result
        result = feed_daily_report.main()
        assert result == True

答案 3 :(得分:0)

以下解决方案对我有用。

def test_connect(env_var_setup, monkeypatch):
    monkeypatch.setattr(snowflake.connector.connection.SnowflakeConnection,
                    "connect", mocked_sf_connect
                    )
    # calling snowflake connector method
    file_job_map(env_var_setup).connect()

#模拟连接

def mocked_sf_connect(self, **kwargs):
    print("Connection Successfully Established")
    return True