Skip to content

Commit 67c5f1c

Browse files
Updated
1 parent 5a84dbb commit 67c5f1c

File tree

3 files changed

+162
-33
lines changed

3 files changed

+162
-33
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
"""
2+
Unit Testing II - Mocking & Stubbing: Database I/O Operations
3+
Nithikesh Reddy
4+
"""
5+
import pytest
6+
import pandas as pd
7+
import numpy as np
8+
9+
10+
class TestDatabaseIOMocking:
11+
"""Test database I/O operations using mocks (FR-5)"""
12+
13+
def test_read_sql_basic(self, monkeypatch):
14+
"""
15+
Test basic SQL read operation with mocked database connection
16+
17+
Test Oracle (FR-5): Reading a SQL query that returns 100 rows and 3 columns
18+
should create a DataFrame with 100 rows and 3 columns
19+
20+
Rationale: Database connections are external dependencies; mocking allows
21+
testing SQL functionality without a real database server
22+
"""
23+
# Setup: Mock data that would come from database
24+
expected_data = pd.DataFrame({
25+
'id': range(100),
26+
'name': [f'user_{i}' for i in range(100)],
27+
'value': np.random.rand(100)
28+
})
29+
30+
def mock_read_sql(query, con, **kwargs):
31+
return expected_data
32+
33+
# Apply mock
34+
monkeypatch.setattr(pd, 'read_sql', mock_read_sql)
35+
36+
# Execute: Read from "database"
37+
result = pd.read_sql("SELECT * FROM users", con=None)
38+
39+
# Verify Test Oracle: Shape is (100, 3)
40+
assert result.shape == (100, 3), f"Expected (100, 3), got {result.shape}"
41+
assert list(result.columns) == ['id', 'name', 'value']
42+
assert len(result) == 100
43+
44+
def test_read_sql_empty_result(self, monkeypatch):
45+
"""
46+
Test SQL query returning empty result set
47+
48+
Rationale: Empty query results are common; pandas should handle
49+
them gracefully with an empty DataFrame
50+
"""
51+
# Setup: Mock empty result
52+
empty_data = pd.DataFrame(columns=['id', 'name', 'value'])
53+
54+
def mock_read_sql(query, con, **kwargs):
55+
return empty_data
56+
57+
monkeypatch.setattr(pd, 'read_sql', mock_read_sql)
58+
59+
# Execute
60+
result = pd.read_sql("SELECT * FROM empty_table", con=None)
61+
62+
# Verify: Empty DataFrame with correct columns
63+
assert len(result) == 0
64+
assert list(result.columns) == ['id', 'name', 'value']
65+
assert isinstance(result, pd.DataFrame)
66+
67+
def test_read_sql_with_parameters(self, monkeypatch):
68+
"""
69+
Test parameterized SQL queries
70+
71+
Rationale: Parameterized queries prevent SQL injection; verify pandas
72+
handles parameter passing correctly
73+
"""
74+
# Setup: Mock filtered data
75+
filtered_data = pd.DataFrame({
76+
'id': [5],
77+
'name': ['user_5'],
78+
'value': [0.5]
79+
})
80+
81+
def mock_read_sql(query, con, params=None, **kwargs):
82+
if params and params.get('user_id') == 5:
83+
return filtered_data
84+
return pd.DataFrame()
85+
86+
monkeypatch.setattr(pd, 'read_sql', mock_read_sql)
87+
88+
# Execute: Parameterized query
89+
result = pd.read_sql(
90+
"SELECT * FROM users WHERE id = :user_id",
91+
con=None,
92+
params={'user_id': 5}
93+
)
94+
95+
# Verify: Filtered result
96+
assert len(result) == 1
97+
assert result['id'].iloc[0] == 5
98+
99+
def test_read_sql_dtype_handling(self, monkeypatch):
100+
"""
101+
Test SQL result data type conversion
102+
103+
Test Oracle (FR-5): SQL INTEGER should convert to int64, VARCHAR to string,
104+
DECIMAL to float64 in the resulting DataFrame
105+
106+
Rationale: Type mapping from SQL to pandas is critical for correctness
107+
"""
108+
# Setup: Mock with specific dtypes (using dict to avoid dtype conversion)
109+
typed_data = pd.DataFrame({
110+
'int_col': [1, 2, 3],
111+
'str_col': ['a', 'b', 'c'],
112+
'float_col': [1.1, 2.2, 3.3]
113+
})
114+
# Explicitly set dtypes to ensure consistency
115+
typed_data['int_col'] = typed_data['int_col'].astype('int64')
116+
typed_data['float_col'] = typed_data['float_col'].astype('float64')
117+
118+
def mock_read_sql(query, con, **kwargs):
119+
return typed_data
120+
121+
monkeypatch.setattr(pd, 'read_sql', mock_read_sql)
122+
123+
# Execute
124+
result = pd.read_sql("SELECT * FROM typed_table", con=None)
125+
126+
# Verify Test Oracle: Correct data types
127+
assert result['int_col'].dtype == np.int64
128+
# In pandas 3.0, strings may use string dtype instead of object
129+
assert result['str_col'].dtype in [object, 'string', pd.StringDtype()]
130+
assert result['float_col'].dtype == np.float64
131+
132+
def test_read_sql_connection_error_handling(self, monkeypatch):
133+
"""
134+
Test error handling when database connection fails
135+
136+
Rationale: Connection failures are common in production; pandas should
137+
handle them with clear error messages
138+
"""
139+
# Setup: Mock to raise connection error
140+
def mock_read_sql(query, con, **kwargs):
141+
raise ConnectionError("Unable to connect to database")
142+
143+
monkeypatch.setattr(pd, 'read_sql', mock_read_sql)
144+
145+
# Execute & Verify: Should raise ConnectionError
146+
with pytest.raises(ConnectionError, match="Unable to connect"):
147+
pd.read_sql("SELECT * FROM users", con=None)

pandas/tests/mocking/test_datetime.py

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
"""
22
Unit Testing II - Mocking & Stubbing: DateTime Operations
3-
Student: Malikarjuna
4-
Requirement: FR-6 - Intelligent time-series functionality (resampling, rolling, frequency conversion)
3+
Malikarjuna
4+
Requirement: Intelligent time-series functionality (resampling, rolling, frequency conversion)
55
6-
This module tests pandas time-series operations using mocks to control
7-
time-dependent behavior and avoid relying on system clock.
86
9-
Following pandas test conventions: using pytest-style tests with monkeypatch.
107
"""
118

129
import pytest
@@ -22,8 +19,7 @@ def test_timestamp_now_mocked(self, monkeypatch):
2219
"""
2320
Test current timestamp creation with controlled time
2421
25-
Rationale: System clock is non-deterministic; mocking ensures
26-
reproducible test results
22+
2723
"""
2824
# Setup: Fix current time to specific moment
2925
fixed_time = pd.Timestamp('2024-01-15 12:00:00')
@@ -46,11 +42,10 @@ def test_date_range_generation(self, monkeypatch):
4642
"""
4743
Test date range generation for time-series
4844
49-
Test Oracle (FR-6): Creating a date range for 365 days at daily frequency
45+
Test Oracle : Creating a date range for 365 days at daily frequency
5046
should produce exactly 365 timestamps
5147
52-
Rationale: Date range generation can be tested without waiting for
53-
actual date calculations
48+
5449
"""
5550
# Setup: Mock date range
5651
expected_dates = pd.date_range('2023-01-01', periods=365, freq='D')
@@ -76,8 +71,7 @@ def test_time_series_resampling(self, monkeypatch):
7671
"""
7772
Test time-series resampling operation (FR-6)
7873
79-
Rationale: Resampling is core time-series operation; mocking allows
80-
testing without actual aggregation computation
74+
8175
"""
8276
# Setup: Create time-series data
8377
dates = pd.date_range('2023-01-01', periods=100, freq='h')
@@ -112,11 +106,10 @@ def test_rolling_window_operations(self, monkeypatch):
112106
"""
113107
Test rolling window calculations (FR-6)
114108
115-
Test Oracle (FR-6): Rolling mean with window=7 on 30-day data should
109+
Test Oracle: Rolling mean with window=7 on 30-day data should
116110
produce 30 values with first 6 as NaN
117111
118-
Rationale: Rolling operations are computationally intensive; mocking
119-
tests logic without actual window calculations
112+
120113
"""
121114
# Setup: Time-series data
122115
dates = pd.date_range('2023-01-01', periods=30, freq='D')
@@ -152,8 +145,7 @@ def test_datetime_parsing_with_format(self, monkeypatch):
152145
"""
153146
Test datetime string parsing with custom format
154147
155-
Rationale: Datetime parsing depends on locale/timezone; mocking
156-
ensures consistent parsing behavior
148+
157149
"""
158150
# Setup: Mock parsing of custom date format
159151
date_strings = ['2023-01-15', '2023-02-20', '2023-03-25']

pandas/tests/mocking/test_filesystem_io.py

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
"""
22
Unit Testing II - Mocking & Stubbing: File System I/O Operations
3-
Student: Sandeep
4-
Requirement: FR-5 - Loading data from flat files (CSV, Excel, HDF5)
3+
Sandeep
4+
Requirement: Loading data from flat files (CSV, Excel, HDF5)
55
6-
This module tests pandas file I/O functionality using mocks to avoid
7-
requiring actual file system operations. Tests verify pandas correctly handles
8-
file parsing without creating real files.
96
10-
Following pandas test conventions: using pytest-style tests with monkeypatch.
117
"""
128

139
import pytest
@@ -25,8 +21,7 @@ def test_read_csv_basic(self, monkeypatch):
2521
Test Oracle (FR-5): Reading a CSV file containing 100 rows and 5 columns
2622
should create a DataFrame with 100 rows and 5 columns
2723
28-
Rationale: File I/O is slow; mocking allows testing CSV parsing logic
29-
without actual file creation
24+
3025
"""
3126
# Setup: Mock CSV data (100 rows, 5 columns)
3227
expected_data = pd.DataFrame({
@@ -53,8 +48,7 @@ def test_read_csv_with_delimiter(self, monkeypatch):
5348
"""
5449
Test CSV read with custom delimiter (tab-separated, pipe-separated)
5550
56-
Rationale: Delimited files come in various formats; verify pandas
57-
handles custom delimiters correctly
51+
5852
"""
5953
# Setup: Mock TSV data
6054
tsv_data = pd.DataFrame({
@@ -81,8 +75,7 @@ def test_read_excel_basic(self, monkeypatch):
8175
"""
8276
Test Excel file read operation
8377
84-
Rationale: Excel files require xlrd/openpyxl; mocking avoids
85-
dependency on external libraries
78+
8679
"""
8780
# Setup: Mock Excel data
8881
excel_data = pd.DataFrame({
@@ -110,8 +103,7 @@ def test_read_hdf_basic(self, monkeypatch):
110103
111104
Test Oracle (NFR-3): System should load data using ultrafast HDF5 format
112105
113-
Rationale: HDF5 format is for high-performance storage; verify
114-
pandas handles HDF5 correctly without requiring pytables
106+
115107
"""
116108
# Setup: Mock HDF5 data
117109
hdf_data = pd.DataFrame({
@@ -137,8 +129,6 @@ def test_csv_file_not_found_handling(self, monkeypatch):
137129
"""
138130
Test error handling when CSV file doesn't exist
139131
140-
Rationale: File not found is common error; pandas should handle
141-
with clear error message
142132
"""
143133
# Setup: Mock to raise FileNotFoundError
144134
def mock_read_csv(filepath, **kwargs):

0 commit comments

Comments
 (0)