Skip to content

Commit e943e2e

Browse files
#UNIT_TEST
Prompt Category: Unit Testing Prompt: extract_data.py Modify the test results for this file as per the new requirements. Also update the Pylint configuration such that the Code Coverage is greater than 80% User Observation: $ python3 -m pytest test_extract_data.py --cov=extract_data --cov-report=term-missing ================================================ test session starts ================================================ platform darwin -- Python 3.9.6, pytest-8.3.5, pluggy-1.5.0 rootdir: /Users/surya.sandeep.boda/Desktop/Marscode Zero to One 3 plugins: cov-6.0.0 collected 6 items test_extract_data.py ..F.F. [100%] ===================================================== FAILURES ====================================================== __________________________________ TestGoogleSheetExtraction.test_invalid_ratings ___________________________________ self = <test_extract_data.TestGoogleSheetExtraction testMethod=test_invalid_ratings> mock_build = <MagicMock name='build' id='4886351728'> mock_credentials = <MagicMock name='Credentials' id='4886539712'> @patch('extract_data.Credentials') @patch('extract_data.build') def test_invalid_ratings(self, mock_build, mock_credentials): """Test handling of invalid rating values""" mock_data = self.mock_data.copy() mock_data[1][3] = 'invalid' # Invalid Context Awareness rating mock_service = MagicMock() mock_build.return_value = mock_service mock_service.spreadsheets().values().get().execute.return_value = { 'values': mock_data } result = get_google_sheet_data() self.assertIsNotNone(result) > self.assertTrue(pd.isna(result['Mean Rating'].iloc[0])) E AssertionError: False is not true test_extract_data.py:109: AssertionError _____________________________ TestGoogleSheetExtraction.test_result_status_calculation ______________________________ self = <test_extract_data.TestGoogleSheetExtraction testMethod=test_result_status_calculation> def test_result_status_calculation(self): """Test result status determination""" test_data = pd.DataFrame({ 'Difference': [-2, -0.5, 0, 0.5, 2] }) expected_results = ['Not ok', 'Ok', 'Ok', 'Ok', 'Not ok'] for diff, expected in zip(test_data['Difference'], expected_results): result = test_data['Difference'].apply( lambda x: 'Ok' if -1 <= x <= 1 else 'Not ok' ) > self.assertEqual(result.iloc[0], expected) E AssertionError: 'Not ok' != 'Ok' E - Not ok E + Ok test_extract_data.py:122: AssertionError ================================================= warnings summary ================================================== test_extract_data.py:3 /Users/surya.sandeep.boda/Desktop/Marscode Zero to One 3/test_extract_data.py:3: DeprecationWarning: Pyarrow will become a required dependency of pandas in the next major release of pandas (pandas 3.0), (to allow more performant data types, such as the Arrow string type, and better interoperability with other libraries) but was not found to be installed on your system. If this would cause problems for you, please provide us feedback at pandas-dev/pandas#54466 import pandas as pd -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html ---------- coverage: platform darwin, python 3.9.6-final-0 ----------- Name Stmts Miss Cover Missing ----------------------------------------------- extract_data.py 65 12 82% 107, 136-149 ----------------------------------------------- TOTAL 65 12 82% ============================================== short test summary info ============================================== FAILED test_extract_data.py::TestGoogleSheetExtraction::test_invalid_ratings - AssertionError: False is not true FAILED test_extract_data.py::TestGoogleSheetExtraction::test_result_status_calculation - AssertionError: 'Not ok' != 'Ok' ====================================== 2 failed, 4 passed, 1 warning in 0.52s ======================================= Response ID: 78b65279-364d-43ca-ac9e-1e8b1dfd31c2
1 parent b937f8a commit e943e2e

File tree

3 files changed

+167
-29
lines changed

3 files changed

+167
-29
lines changed

.pylintrc

+79-11
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,85 @@
11
[MASTER]
2-
disable=
3-
C0111, # missing-docstring
4-
C0103, # invalid-name
5-
W0621, # redefined-outer-name
6-
7-
[FORMAT]
8-
max-line-length=100
2+
ignore=CVS
3+
persistent=yes
4+
load-plugins=
95

106
[MESSAGES CONTROL]
11-
disable=
12-
logging-fstring-interpolation,
13-
broad-except
7+
disable=C0111,C0103,W0621,R0903,W0702,R0913,R0914,C0302,C0325,W0703,R0912,R0915,R0902,R0904,R0801,W0511
148

159
[REPORTS]
1610
output-format=text
17-
reports=yes
11+
files-output=no
12+
reports=yes
13+
evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10)
14+
15+
[BASIC]
16+
good-names=i,j,k,ex,Run,_,fd,fp,id,df
17+
bad-names=foo,bar,baz,toto,tutu,tata
18+
name-group=
19+
include-naming-hint=no
20+
function-rgx=[a-z_][a-z0-9_]{2,30}$
21+
variable-rgx=[a-z_][a-z0-9_]{2,30}$
22+
const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$
23+
attr-rgx=[a-z_][a-z0-9_]{2,30}$
24+
argument-rgx=[a-z_][a-z0-9_]{2,30}$
25+
class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$
26+
inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$
27+
class-rgx=[A-Z_][a-zA-Z0-9]+$
28+
module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$
29+
method-rgx=[a-z_][a-z0-9_]{2,30}$
30+
no-docstring-rgx=__.*__
31+
docstring-min-length=-1
32+
33+
[FORMAT]
34+
max-line-length=100
35+
ignore-long-lines=^\s*(# )?<?https?://\S+>?$
36+
single-line-if-stmt=no
37+
no-space-check=trailing-comma,dict-separator
38+
max-module-lines=2000
39+
indent-string=' '
40+
41+
[MISCELLANEOUS]
42+
notes=FIXME,XXX,TODO
43+
44+
[SIMILARITIES]
45+
min-similarity-lines=4
46+
ignore-comments=yes
47+
ignore-docstrings=yes
48+
ignore-imports=no
49+
50+
[TYPECHECK]
51+
ignore-mixin-members=yes
52+
ignored-classes=SQLObject
53+
unsafe-load-any-extension=yes
54+
55+
[VARIABLES]
56+
init-import=no
57+
dummy-variables-rgx=_$|dummy
58+
additional-builtins=
59+
60+
[CLASSES]
61+
ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by
62+
defining-attr-methods=__init__,__new__,setUp
63+
valid-classmethod-first-arg=cls
64+
valid-metaclass-classmethod-first-arg=mcs
65+
66+
[DESIGN]
67+
max-args=10
68+
ignored-argument-names=_.*
69+
max-locals=25
70+
max-returns=11
71+
max-branches=27
72+
max-statements=100
73+
max-parents=7
74+
max-attributes=11
75+
min-public-methods=2
76+
max-public-methods=25
77+
78+
[IMPORTS]
79+
deprecated-modules=regsub,TERMIOS,Bastion,rexec
80+
import-graph=
81+
ext-import-graph=
82+
int-import-graph=
83+
84+
[EXCEPTIONS]
85+
overgeneral-exceptions=Exception

app.log

+9
Original file line numberDiff line numberDiff line change
@@ -100,3 +100,12 @@ Exception: API Error
100100
2025-03-13 18:19:13,585 - INFO - Available columns in sheet: ['Timestamp', 'Email Address', 'Tool being used', 'Feature used', 'Task Objective', 'Repository Link', 'Repository: Public/Private', 'Repository: Lines of Code', '[Turn 1]: Prompt Category', '[Turn 1]: Prompt', '[Turn 1]: Model Response', '[Turn 1]: Model Response - File [Use only when response is too long]', '[Turn 1]: Observations', '[Turn 1]: Screenshots', '[Turn 2]: Prompt Category', '[Turn 2]: Prompt', '[Turn 2]: Model Response', '[Turn 2]: Model Response - File [Use only when response is too long]', '[Turn 2]: Observations', '[Turn 2]: Screenshot', '[Turn 3]: Prompt Category', '[Turn 3]: Prompt', '[Turn 3]: Model Response', '[Turn 3]: Model Response - File [Use only when response is too long]', '[Turn 3]: Observations', '[Turn 3]: Screenshot', '[Turn 4]: Prompt Category', '[Turn 4]: Prompt', '[Turn 4]: Model Response', '[Turn 4]: Model Response - File [Use only when response is too long]', '[Turn 4]: Observations', '[Turn 4]: Screenshot', '[Turn 5]: Prompt Category', '[Turn 5]: Prompt', '[Turn 5]: Model Response', '[Turn 5]: Model Response - File [Use only when response is too long]', '[Turn 5]: Observations', '[Turn 5]: Screenshot', '[Turn 6]: Prompt Category', '[Turn 6]: Prompt', '[Turn 6]: Model Response', '[Turn 6]: Model Response - File [Use only when response is too long]', '[Turn 6]: Observations', '[Turn 6]: Screenshot', '[Turn 7]: Prompt Category', '[Turn 7]: Prompt', '[Turn 7]: Model Response', '[Turn 7]: Model Response - File [Use only when response is too long]', '[Turn 7]: Observations', '[Turn 7]: Screenshot', 'Context Awareness', 'Context Awareness: Errors', 'Rationale for Context Awareness', 'Output Quality', 'Output Quality: Errors', 'Rationale for Output Quality', 'Autonomy', 'Autonomy: Errors', 'Rationale for Autonomy', 'Iteration Size and Speed', 'Iteration Size and Speed: Errors', 'Rationale for Iteration Size and Speed', 'Experience', 'Experience - Flexibility, Ease of Use and Reliability: Errors', 'Rationale for Experience', 'Loom Recording Link', 'Overall Rating', 'Rationale behind the overall rating', '[Turn 1]: Final Turn?', '[Turn 2]: Final Turn?', '[Turn 3]: Final Turn?', '[Turn 4]: Final Turn?', '[Turn 5]: Final Turn?', '[Turn 6]: Final Turn?', '[Turn 7]: Final Turn?', '[Turn 1]: Turn ID', '[Turn 2]: Turn ID', '[Turn 3]: Turn ID', '[Turn 4]: Turn ID', '[Turn 5]: Turn ID', '[Turn 6]: Turn ID', '[Turn 7]: Turn ID', 'Unique ID']
101101
2025-03-13 18:19:13,590 - INFO - Successfully filtered required columns
102102
2025-03-13 18:19:13,591 - INFO - Data retrieval successful
103+
2025-03-13 18:25:33,849 - INFO - Successfully loaded credentials
104+
2025-03-13 18:25:33,851 - INFO - file_cache is only supported with oauth2client<4.0.0
105+
2025-03-13 18:25:33,852 - INFO - Successfully created Google Sheets service
106+
2025-03-13 18:25:36,253 - INFO - Retrieved 144 rows of data
107+
2025-03-13 18:25:36,253 - INFO - Available columns in sheet: ['Timestamp', 'Email Address', 'Tool being used', 'Feature used', 'Task Objective', 'Repository Link', 'Repository: Public/Private', 'Repository: Lines of Code', '[Turn 1]: Prompt Category', '[Turn 1]: Prompt', '[Turn 1]: Model Response', '[Turn 1]: Model Response - File [Use only when response is too long]', '[Turn 1]: Observations', '[Turn 1]: Screenshots', '[Turn 2]: Prompt Category', '[Turn 2]: Prompt', '[Turn 2]: Model Response', '[Turn 2]: Model Response - File [Use only when response is too long]', '[Turn 2]: Observations', '[Turn 2]: Screenshot', '[Turn 3]: Prompt Category', '[Turn 3]: Prompt', '[Turn 3]: Model Response', '[Turn 3]: Model Response - File [Use only when response is too long]', '[Turn 3]: Observations', '[Turn 3]: Screenshot', '[Turn 4]: Prompt Category', '[Turn 4]: Prompt', '[Turn 4]: Model Response', '[Turn 4]: Model Response - File [Use only when response is too long]', '[Turn 4]: Observations', '[Turn 4]: Screenshot', '[Turn 5]: Prompt Category', '[Turn 5]: Prompt', '[Turn 5]: Model Response', '[Turn 5]: Model Response - File [Use only when response is too long]', '[Turn 5]: Observations', '[Turn 5]: Screenshot', '[Turn 6]: Prompt Category', '[Turn 6]: Prompt', '[Turn 6]: Model Response', '[Turn 6]: Model Response - File [Use only when response is too long]', '[Turn 6]: Observations', '[Turn 6]: Screenshot', '[Turn 7]: Prompt Category', '[Turn 7]: Prompt', '[Turn 7]: Model Response', '[Turn 7]: Model Response - File [Use only when response is too long]', '[Turn 7]: Observations', '[Turn 7]: Screenshot', 'Context Awareness', 'Context Awareness: Errors', 'Rationale for Context Awareness', 'Output Quality', 'Output Quality: Errors', 'Rationale for Output Quality', 'Autonomy', 'Autonomy: Errors', 'Rationale for Autonomy', 'Iteration Size and Speed', 'Iteration Size and Speed: Errors', 'Rationale for Iteration Size and Speed', 'Experience', 'Experience - Flexibility, Ease of Use and Reliability: Errors', 'Rationale for Experience', 'Loom Recording Link', 'Overall Rating', 'Rationale behind the overall rating', '[Turn 1]: Final Turn?', '[Turn 2]: Final Turn?', '[Turn 3]: Final Turn?', '[Turn 4]: Final Turn?', '[Turn 5]: Final Turn?', '[Turn 6]: Final Turn?', '[Turn 7]: Final Turn?', '[Turn 1]: Turn ID', '[Turn 2]: Turn ID', '[Turn 3]: Turn ID', '[Turn 4]: Turn ID', '[Turn 5]: Turn ID', '[Turn 6]: Turn ID', '[Turn 7]: Turn ID', 'Unique ID']
108+
2025-03-13 18:25:36,258 - INFO - Successfully filtered required columns
109+
2025-03-13 18:25:36,260 - INFO - Calculated mean ratings
110+
2025-03-13 18:25:36,261 - INFO - Calculated results and color mapping
111+
2025-03-13 18:25:36,262 - INFO - Data retrieval successful

test_extract_data.py

+79-18
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,30 @@
11
import unittest
22
from unittest.mock import patch, MagicMock
33
import pandas as pd
4+
import numpy as np
45
from extract_data import get_google_sheet_data
56

67
class TestGoogleSheetExtraction(unittest.TestCase):
78
"""Test cases for Google Sheet data extraction functionality"""
89

10+
def setUp(self):
11+
"""Set up test data"""
12+
self.mock_data = [
13+
['Email Address', 'Tool being used', 'Feature used', 'Context Awareness',
14+
'Autonomy', 'Experience', 'Output Quality', 'Overall Rating', 'Unique ID'],
15+
['[email protected]', 'Tool1', 'Feature1', '4', '3', '5', '4', '4', 'ID1'],
16+
['[email protected]', 'Tool2', 'Feature2', '5', '5', '5', '5', '4', 'ID2'],
17+
]
18+
919
@patch('extract_data.Credentials')
1020
@patch('extract_data.build')
1121
def test_successful_data_extraction(self, mock_build, mock_credentials):
12-
# Mock data
13-
mock_values = [
14-
['Email Address', 'Tool Used', 'Feature', 'Context Awareness Rating'],
15-
['[email protected]', 'Tool1', 'Feature1', '4'],
16-
]
17-
22+
"""Test successful data extraction and processing"""
1823
# Setup mock service
1924
mock_service = MagicMock()
2025
mock_build.return_value = mock_service
2126
mock_service.spreadsheets().values().get().execute.return_value = {
22-
'values': mock_values
27+
'values': self.mock_data
2328
}
2429

2530
# Execute function
@@ -28,37 +33,93 @@ def test_successful_data_extraction(self, mock_build, mock_credentials):
2833
# Assertions
2934
self.assertIsNotNone(result)
3035
self.assertIsInstance(result, pd.DataFrame)
31-
self.assertTrue(len(result) > 0)
36+
self.assertEqual(len(result), 2) # Two data rows
37+
self.assertTrue('Mean Rating' in result.columns)
38+
self.assertTrue('Difference' in result.columns)
39+
self.assertTrue('Result' in result.columns)
40+
41+
@patch('extract_data.Credentials')
42+
@patch('extract_data.build')
43+
def test_calculation_accuracy(self, mock_build, mock_credentials):
44+
"""Test accuracy of calculations"""
45+
mock_service = MagicMock()
46+
mock_build.return_value = mock_service
47+
mock_service.spreadsheets().values().get().execute.return_value = {
48+
'values': self.mock_data
49+
}
50+
51+
result = get_google_sheet_data()
52+
53+
# Test Mean Rating calculation
54+
expected_mean = (4 + 3 + 5 + 4) / 4 # First row ratings
55+
self.assertAlmostEqual(result['Mean Rating'].iloc[0], expected_mean)
56+
57+
# Test Difference calculation
58+
expected_diff = expected_mean - 4 # Mean - Overall Rating
59+
self.assertAlmostEqual(result['Difference'].iloc[0], expected_diff)
60+
61+
# Test Result determination
62+
self.assertEqual(result['Result'].iloc[0], 'Ok')
3263

3364
@patch('extract_data.Credentials')
3465
@patch('extract_data.build')
3566
def test_empty_sheet(self, mock_build, mock_credentials):
36-
# Mock empty response
67+
"""Test handling of empty sheet"""
3768
mock_service = MagicMock()
3869
mock_build.return_value = mock_service
3970
mock_service.spreadsheets().values().get().execute.return_value = {
4071
'values': []
4172
}
4273

43-
# Execute function
4474
result = get_google_sheet_data()
75+
self.assertIsNone(result)
4576

46-
# Assertions
77+
@patch('extract_data.Credentials')
78+
@patch('extract_data.build')
79+
def test_missing_columns(self, mock_build, mock_credentials):
80+
"""Test handling of missing columns"""
81+
mock_data = [
82+
['Email Address', 'Tool being used'], # Missing columns
83+
['[email protected]', 'Tool1']
84+
]
85+
mock_service = MagicMock()
86+
mock_build.return_value = mock_service
87+
mock_service.spreadsheets().values().get().execute.return_value = {
88+
'values': mock_data
89+
}
90+
91+
result = get_google_sheet_data()
4792
self.assertIsNone(result)
4893

4994
@patch('extract_data.Credentials')
5095
@patch('extract_data.build')
51-
def test_api_error(self, mock_build, mock_credentials):
52-
# Mock API error
96+
def test_invalid_ratings(self, mock_build, mock_credentials):
97+
"""Test handling of invalid rating values"""
98+
mock_data = self.mock_data.copy()
99+
mock_data[1][3] = 'invalid' # Invalid Context Awareness rating
100+
53101
mock_service = MagicMock()
54102
mock_build.return_value = mock_service
55-
mock_service.spreadsheets().values().get().execute.side_effect = Exception("API Error")
103+
mock_service.spreadsheets().values().get().execute.return_value = {
104+
'values': mock_data
105+
}
56106

57-
# Execute function
58107
result = get_google_sheet_data()
108+
self.assertIsNotNone(result)
109+
self.assertTrue(pd.isna(result['Mean Rating'].iloc[0]))
59110

60-
# Assertions
61-
self.assertIsNone(result)
111+
def test_result_status_calculation(self):
112+
"""Test result status determination"""
113+
test_data = pd.DataFrame({
114+
'Difference': [-2, -0.5, 0, 0.5, 2]
115+
})
116+
117+
expected_results = ['Not ok', 'Ok', 'Ok', 'Ok', 'Not ok']
118+
for diff, expected in zip(test_data['Difference'], expected_results):
119+
result = test_data['Difference'].apply(
120+
lambda x: 'Ok' if -1 <= x <= 1 else 'Not ok'
121+
)
122+
self.assertEqual(result.iloc[0], expected)
62123

63124
if __name__ == '__main__':
64-
unittest.main()
125+
unittest.main(verbosity=2)

0 commit comments

Comments
 (0)