我有我的python课
class FetchData:
def __init__(self, spark):
self.spark = spark
def filter_data_from_s3(self, table_name, s3_location, sql_query, table_schema, partition_column):
# DO SOMETHING
另一个调用此类的文件是FilterData.py
from accessor.FetchData import FetchData
from pyspark.sql import SparkSession
import sys
def main(args):
spark = SparkSession \
.builder \
.appName("ROAD") \
.config(conf=sparkConf) \
.getOrCreate()
try:
args_map = DataUtils.parse_args(args)
logger.info("Parsed Argument Map for Filtering Data : {}".format(args_map))
f = FetchData(spark)
for table in table_list:
table_name = table.get("table_name")
s3_location = table.get("s3_location")
sql_query = DataUtils.un_parametrize(table.get("sql_query"), args_map)
table_schema = table.get("table_schema", args)
f.filter_data_from_s3(table_name=table_name,
s3_location=s3_location,
sql_query=sql_query,
table_schema=table_schema,
partition_column=args_map.get('partition_column'))
finally:
spark.stop()
if __name__ == "__main__":
main(sys.argv)
我已经写了一个测试用例来测试filterData.py主要功能
我想模拟filter_data_from_s3调用。
这是我写的测试用例-
class TestFilterData(unittest.TestCase):
@patch('accessor.FetchData')
def test_main_call_times_for_na(self, fetch_data_mock):
print(fetch_data_mock)
spark_session = get_spark_session()
CUSTOMER_ACCESS_SCHEMA = StructType(
[StructField('enc_customer_id', StringType(), False),
StructField('marketplace_id', IntegerType(), False)]
)
df = spark_session.createDataFrame([
("customerid1", 1),
("customerid1", 2),
("customerid2", 2)
], CUSTOMER_ACCESS_SCHEMA)
fetch_data_mock.filter_data_from_s3.return_value = df
test_args = ["", "--run_date=2018-09-01", "--num_days=730",
"--region=NA", "--marketplace_id=1", "--region_id=1", "--num_asins=1000"]
FilterData.main(test_args)
if __name__ == '__main__':
unittest.main()
当我调用测试用例时,它实际上会调用过滤数据并失败。而是我想调用我的模拟方法。
我是python的新手,现在大约一天都面临这个问题。谁能告诉我我在做什么错。
最佳答案
如果要从main()
测试filterData.py
,则应该在FetchData
中模拟filterData.py
。也就是说,应将@patch('accessor.FetchData')
代替@patch('filterData.FetchData')
总是在使用对象时对其进行嘲笑,而不是在其起源处进行嘲笑。
您遇到的问题是,即使您正在修补符号accessor.FetchData
以指向其他对象(模拟对象),在测试中应用该指令时,被测模块filterData
都具有已经在其命名空间中导入了对原始对象的引用。现在,将原始模块的FetchData
符号更改为其他符号都没关系,它不会影响filterData
的命名空间。如果要filterData
丢失原始引用并指向您的模拟,则必须将其自己的FetchData
符号指向该模拟。
编辑
根据您的代码使用FetchData
的方式,这就是我要为所需的自省类型设置模拟程序的方式。
import mock
@mock.patch('filterData.FetchData')
def test_main_call_times_for_na(self, fetch_data_mock):
spark_session = get_spark_session()
CUSTOMER_ACCESS_SCHEMA = StructType(
[StructField('enc_customer_id', StringType(), False),
StructField('marketplace_id', IntegerType(), False)]
)
df = spark_session.createDataFrame([
("customerid1", 1),
("customerid1", 2),
("customerid2", 2)
], CUSTOMER_ACCESS_SCHEMA)
fake_f = mock.Mock()
fake_f.filter_data_from_s3.return_value = df
# ensuring that I also control the instance returned by filterData.FetchData
fetch_data_mock.return_value = fake_f
test_args = ["", "--run_date=2018-09-01", "--num_days=730",
"--region=NA", "--marketplace_id=1", "--region_id=1", "--num_asins=1000"]
FilterData.main(test_args)
assert fake_f.filter_data_from_s3.call_count==11
关于python - 没有为类分配Python Mock,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/52342533/