Strategies for testing PySpark applications
Instruction: Describe the strategies and frameworks you would use for testing PySpark applications, covering unit tests, integration tests, and end-to-end tests.
Updated
Separate pure Python tests from Spark-semantic tests. Mocks can check orchestration or simulate a client failure, but a mocked DataFrame does not execute Catalyst expressions, joins, null rules or serialization. Test transformations with a real isolated local Spark session and small explicit fixtures.
For Spark 3.5+ with its testing-helper dependencies installed (including compatible pandas/PyArrow where required) and an existing local session named spark, this executable test checks both duplicate multiplicity and null filtering:
from pyspark.sql import functions as F
from pyspark.testing.utils import assertDataFrameEqual, assertSchemaEqual
def accepted(df):
return df.filter(F.col('amount') > 0).select('id', 'amount')
source = spark.createDataFrame([
(1, 2.0), (1, 2.0), (2, None), (3, -1.0), (4, 0.0)
], 'id int, amount double')
expected = spark.createDataFrame([(1, 2.0), (1, 2.0)], 'id int, amount double')
actual = accepted(source)
assertSchemaEqual(actual.schema, expected.schema)
assertDataFrameEqual(actual, expected, checkRowOrder=False, rtol=0, atol=0)
assertDataFrameEqual(accepted(source.limit(0)), expected.limit(0))
The example tests a positive-filter function, not a complete amount validator. In Spark, NaN and positive infinity can satisfy amount > 0; explicitly reject nonfinite values when the data contract requires finite amounts. The testing helpers' options vary by Spark version; check whether nullable metadata is compared and assert exact schema JSON when that is required.
Use independent expected rows or mathematical oracles, not the same transformation to generate expected output. Test duplicate keys, empty/all-null inputs, NaN, malformed values, ordering ties, overflow/ANSI behavior and time-zone boundaries as relevant. Without an explicit ordering contract, compare row multisets, not a presumed collection order. Approximate numerical tolerances must be justified.
Integration tests should exercise actual file formats, schema evolution, connectors and sink commit/idempotency behavior in isolated systems. Streaming tests need replay, late data, duplicate delivery, checkpoint restart and failures during output publication. End-to-end tests reconcile source to accepted/quarantined/published data and run the real entry point.
Pin runtime/dependencies and make tests deterministic. Local tests establish bounded semantics, not distributed scale, connector security or production performance; those require a representative controlled environment and explicit measurements.