您可以通过在测试套件中的 DataFrame 上运行您的代码并比较 DataFrame 列相等或两个整个 DataFrame 的相等来测试 PySpark 代码。
quinn project has several examples。
为测试套件创建 SparkSession
使用此夹具创建一个 tests/conftest.py 文件,以便您可以在测试中轻松访问 SparkSession。
import pytest
from pyspark.sql import SparkSession
@pytest.fixture(scope='session')
def spark():
return SparkSession.builder \
.master("local") \
.appName("chispa") \
.getOrCreate()
列相等示例
假设您想测试以下从字符串中删除所有非单词字符的函数。
def remove_non_word_characters(col):
return F.regexp_replace(col, "[^\\w\\s]+", "")
您可以使用chispa 库中定义的assert_column_equality 函数来测试此函数。
def test_remove_non_word_characters(spark):
data = [
("jo&&se", "jose"),
("**li**", "li"),
("#::luisa", "luisa"),
(None, None)
]
df = spark.createDataFrame(data, ["name", "expected_name"])\
.withColumn("clean_name", remove_non_word_characters(F.col("name")))
assert_column_equality(df, "clean_name", "expected_name")
DataFrame 相等示例
有些功能需要通过比较整个 DataFrame 来进行测试。这是一个对 DataFrame 中的列进行排序的函数。
def sort_columns(df, sort_order):
sorted_col_names = None
if sort_order == "asc":
sorted_col_names = sorted(df.columns)
elif sort_order == "desc":
sorted_col_names = sorted(df.columns, reverse=True)
else:
raise ValueError("['asc', 'desc'] are the only valid sort orders and you entered a sort order of '{sort_order}'".format(
sort_order=sort_order
))
return df.select(*sorted_col_names)
这是你要为这个函数编写的一个测试。
def test_sort_columns_asc(spark):
source_data = [
("jose", "oak", "switch"),
("li", "redwood", "xbox"),
("luisa", "maple", "ps4"),
]
source_df = spark.createDataFrame(source_data, ["name", "tree", "gaming_system"])
actual_df = T.sort_columns(source_df, "asc")
expected_data = [
("switch", "jose", "oak"),
("xbox", "li", "redwood"),
("ps4", "luisa", "maple"),
]
expected_df = spark.createDataFrame(expected_data, ["gaming_system", "name", "tree"])
assert_df_equality(actual_df, expected_df)
测试 I/O
通常最好从 I/O 函数中抽象出代码逻辑,这样更容易测试。
假设你有这样一个函数。
def your_big_function:
df = spark.read.parquet("some_directory")
df2 = df.withColumn(...).transform(function1).transform(function2)
df2.write.parquet("other directory")
最好像这样重构代码:
def all_logic(df):
return df.withColumn(...).transform(function1).transform(function2)
def your_formerly_big_function:
df = spark.read.parquet("some_directory")
df2 = df.transform(all_logic)
df2.write.parquet("other directory")
这样设计您的代码可以让您轻松测试all_logic 函数与上面提到的列相等或DataFrame 相等函数。您可以使用模拟来测试your_formerly_big_function。通常最好在测试套件中避免 I/O(但有时是不可避免的)。