How do I test pandas code and compare DataFrames in a test?
Short answer
Use pandas.testing.assert_frame_equal, which compares values, dtypes, columns and index and reports exactly what differs. Comparing frames with == or assert does not work, because it returns a frame of booleans.
The short version
Use pandas.testing.assert_frame_equal to compare an actual DataFrame with an expected one. It checks values, dtypes, column names and the index, and raises a detailed error showing exactly what differs. A plain assert actual == expected does not work, because comparing frames returns a frame of booleans, not a single truth value.
The correct comparison
import pandas as pd
from pandas.testing import assert_frame_equal
def add_total(df):
return df.assign(total=df["price"] * df["qty"])
def test_add_total():
given = pd.DataFrame({"price": [2, 5], "qty": [3, 1]})
expected = pd.DataFrame({"price": [2, 5], "qty": [3, 1], "total": [6, 5]})
assert_frame_equal(add_total(given), expected)
If they match, the test passes silently. If not, the error message points to the exact column and row that differ, which saves a great deal of debugging.
Why == does not work
actual == expected # a DataFrame of True/False, not one answer
assert actual == expected # ValueError: truth value is ambiguous
Python cannot reduce a frame of booleans to a single True, so it refuses. assert_frame_equal exists precisely to do this comparison properly.
It checks dtypes too, which is stricter than you expect
assert_frame_equal(
pd.DataFrame({"x": [1]}), # int64
pd.DataFrame({"x": [1.0]}), # float64
) # AssertionError: dtype mismatch
This strictness is a feature: an integer column that has quietly become a float usually means a missing value crept in somewhere. If the difference is genuinely irrelevant to your test, relax it with check_dtype=False, but consider first whether the dtype change is telling you about a real bug.
Useful relaxations
Real tests often need to ignore incidental differences.
assert_frame_equal(actual, expected, check_like=True) # ignore column and row order
assert_frame_equal(actual, expected, check_exact=False) # allow tiny float differences
check_exact=False matters for floating point, where a computed 0.30000000000000004 will never exactly equal 0.3. Comparing floats exactly is the classic cause of a test that fails for no real reason.
The index is compared too
A frequent surprise is a test failing because the actual frame has an index of 0, 3, 7 after filtering, while the expected has 0, 1, 2. That is a real difference, and often you should fix the code with reset_index(drop=True) rather than the test, because a stale index can cause misalignment later.
Series and index versions
There are matching helpers for the other pandas objects: assert_series_equal and assert_index_equal. Use the one that matches what your function returns, so the error messages stay specific.
Why test data code at all
Data pipelines fail silently: a wrong join drops rows, a bad fill skews a mean, and nothing raises. Small tests on tiny, hand-written frames catch these regressions the moment they appear, which is far cheaper than discovering a wrong number in a report months later.