Skip to content

Commit d9c7605

Browse files
committed
Fix: improve test structure and add test runner to handle PyO3 import issues
1 parent 8761a0f commit d9c7605

File tree

3 files changed

+171
-80
lines changed

3 files changed

+171
-80
lines changed

run_tests.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Simple test runner to avoid PyO3 import issues.
4+
"""
5+
6+
import subprocess
7+
import sys
8+
import os
9+
10+
def run_tests():
11+
"""Run tests using subprocess to avoid PyO3 issues."""
12+
print("Running tests to avoid PyO3 import issues...")
13+
14+
# Run basic functionality test first
15+
print("\n1. Running basic functionality test...")
16+
result1 = subprocess.run([sys.executable, "test_basic_functionality.py"],
17+
capture_output=True, text=True)
18+
19+
if result1.returncode == 0:
20+
print("✅ Basic functionality test passed")
21+
print(result1.stdout)
22+
else:
23+
print("❌ Basic functionality test failed")
24+
print(result1.stderr)
25+
26+
# Run improved modules tests
27+
print("\n2. Running improved modules tests...")
28+
result2 = subprocess.run([sys.executable, "-m", "pytest",
29+
"tests/test_improved_modules.py", "-v"],
30+
capture_output=True, text=True)
31+
32+
if result2.returncode == 0:
33+
print("✅ Improved modules tests passed")
34+
print(result2.stdout)
35+
else:
36+
print("❌ Improved modules tests failed")
37+
print(result2.stderr)
38+
39+
# Run multi-issue tests
40+
print("\n3. Running multi-issue tests...")
41+
result3 = subprocess.run([sys.executable, "-m", "pytest",
42+
"tests/test_multi_issue_upload_with_subtasks.py", "-v"],
43+
capture_output=True, text=True)
44+
45+
if result3.returncode == 0:
46+
print("✅ Multi-issue tests passed")
47+
print(result3.stdout)
48+
else:
49+
print("❌ Multi-issue tests failed")
50+
print(result3.stderr)
51+
52+
# Summary
53+
print("\n" + "="*50)
54+
print("TEST SUMMARY")
55+
print("="*50)
56+
print(f"Basic functionality: {'✅ PASS' if result1.returncode == 0 else '❌ FAIL'}")
57+
print(f"Improved modules: {'✅ PASS' if result2.returncode == 0 else '❌ FAIL'}")
58+
print(f"Multi-issue: {'✅ PASS' if result3.returncode == 0 else '❌ FAIL'}")
59+
60+
total_failures = sum(1 for r in [result1, result2, result3] if r.returncode != 0)
61+
if total_failures == 0:
62+
print("\n🎉 All tests passed!")
63+
return 0
64+
else:
65+
print(f"\n⚠️ {total_failures} test suite(s) failed")
66+
return 1
67+
68+
if __name__ == "__main__":
69+
sys.exit(run_tests())

tests/test_improved_modules.py

Lines changed: 74 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from unittest.mock import Mock, patch
77
import tempfile
88
import os
9+
import sys
910
from atlassian.errors import ApiError
1011

1112
# Mock the atlassian import to avoid real network calls
@@ -16,6 +17,7 @@
1617
"atlassian.errors": Mock(),
1718
},
1819
):
20+
# Import modules after mocking
1921
from src.config import JiraConfig, AppConfig # noqa
2022
from src.models import JiraIssueData, JiraSubtaskData, CSVRow
2123
from src.csv_processor import CSVProcessor
@@ -214,10 +216,9 @@ class TestJiraClient(unittest.TestCase):
214216

215217
def setUp(self):
216218
"""Set up test fixtures."""
217-
self.jira_patcher = patch("src.jira_client.Jira")
218-
self.mock_jira_class = self.jira_patcher.start()
219-
self.mock_jira_instance = self.mock_jira_class.return_value
220-
219+
# Don't patch during setup to avoid PyO3 issues
220+
# We'll patch in individual test methods instead
221+
221222
with patch.dict(
222223
os.environ,
223224
{
@@ -226,81 +227,93 @@ def setUp(self):
226227
"JIRA_API_TOKEN": "test-token",
227228
},
228229
):
230+
# Import JiraClient here to avoid PyO3 issues
231+
from src.jira_client import JiraClient
229232
self.client = JiraClient()
230-
self.client.jira = self.mock_jira_instance
231-
232-
def tearDown(self):
233-
"""Tear down test fixtures."""
234-
self.jira_patcher.stop()
235233

236234
def test_test_connection_success(self):
237235
"""Test successful connection test."""
238-
self.mock_jira_instance.server_info.return_value = {
239-
"serverTitle": "Test Server"
240-
}
241-
self.assertTrue(self.client.test_connection())
236+
with patch("src.jira_client.Jira") as mock_jira_class:
237+
mock_jira_instance = mock_jira_class.return_value
238+
mock_jira_instance.server_info.return_value = {
239+
"serverTitle": "Test Server"
240+
}
241+
self.client.jira = mock_jira_instance
242+
self.assertTrue(self.client.test_connection())
242243

243244
def test_test_connection_failure(self):
244245
"""Test failed connection test."""
245-
self.mock_jira_instance.server_info.side_effect = Exception(
246-
"Connection failed"
247-
)
248-
self.assertFalse(self.client.test_connection())
246+
with patch("src.jira_client.Jira") as mock_jira_class:
247+
mock_jira_instance = mock_jira_class.return_value
248+
mock_jira_instance.server_info.side_effect = Exception(
249+
"Connection failed"
250+
)
251+
self.client.jira = mock_jira_instance
252+
self.assertFalse(self.client.test_connection())
249253

250254
def test_create_issue_success(self):
251255
"""Test successful issue creation."""
252-
self.mock_jira_instance.issue_create.return_value = {
253-
"key": "TEST-123",
254-
"id": "12345",
255-
}
256-
257-
issue_data = JiraIssueData(
258-
project_key="TEST",
259-
summary="Test Issue",
260-
description="Test Description",
261-
issue_type="Task",
262-
)
263-
created_issue = self.client.create_issue(issue_data.model_dump())
256+
with patch("src.jira_client.Jira") as mock_jira_class:
257+
mock_jira_instance = mock_jira_class.return_value
258+
mock_jira_instance.issue_create.return_value = {
259+
"key": "TEST-123",
260+
"id": "12345",
261+
}
262+
self.client.jira = mock_jira_instance
263+
264+
issue_data = JiraIssueData(
265+
project_key="TEST",
266+
summary="Test Issue",
267+
description="Test Description",
268+
issue_type="Task",
269+
)
270+
created_issue = self.client.create_issue(issue_data.model_dump())
264271

265-
self.assertIsNotNone(created_issue)
266-
self.assertEqual(created_issue["key"], "TEST-123")
267-
self.mock_jira_instance.issue_create.assert_called_once()
272+
self.assertIsNotNone(created_issue)
273+
self.assertEqual(created_issue["key"], "TEST-123")
274+
mock_jira_instance.issue_create.assert_called_once()
268275

269276
def test_create_issue_failure(self):
270277
"""Test failed issue creation."""
271-
# Create a mock ApiError that inherits from Exception
272-
mock_api_error = Exception("Server Error")
273-
mock_api_error.status_code = 500
274-
self.mock_jira_instance.issue_create.side_effect = mock_api_error
275-
276-
issue_data = JiraIssueData(
277-
project_key="TEST",
278-
summary="Test Issue",
279-
description="Test Description",
280-
issue_type="Task",
281-
)
282-
with self.assertRaises(Exception):
283-
self.client.create_issue(issue_data.model_dump())
278+
with patch("src.jira_client.Jira") as mock_jira_class:
279+
mock_jira_instance = mock_jira_class.return_value
280+
# Create a mock exception with status_code
281+
mock_exception = Exception("Server Error")
282+
mock_exception.status_code = 500
283+
mock_jira_instance.issue_create.side_effect = mock_exception
284+
self.client.jira = mock_jira_instance
285+
286+
issue_data = JiraIssueData(
287+
project_key="TEST",
288+
summary="Test Issue",
289+
description="Test Description",
290+
issue_type="Task",
291+
)
292+
with self.assertRaises(Exception):
293+
self.client.create_issue(issue_data.model_dump())
284294

285295
def test_create_subtask_success(self):
286296
"""Test successful subtask creation."""
287-
self.mock_jira_instance.issue_create.return_value = {
288-
"key": "TEST-124",
289-
"id": "12346",
290-
}
291-
292-
subtask_data = JiraSubtaskData(
293-
project_key="TEST",
294-
summary="Test Subtask",
295-
description="Test Subtask Description",
296-
issue_type="Sub-task",
297-
parent_id="TEST-123",
298-
)
299-
created_subtask = self.client.create_subtask(subtask_data.model_dump())
297+
with patch("src.jira_client.Jira") as mock_jira_class:
298+
mock_jira_instance = mock_jira_class.return_value
299+
mock_jira_instance.issue_create.return_value = {
300+
"key": "TEST-124",
301+
"id": "12346",
302+
}
303+
self.client.jira = mock_jira_instance
304+
305+
subtask_data = JiraSubtaskData(
306+
project_key="TEST",
307+
summary="Test Subtask",
308+
description="Test Subtask Description",
309+
issue_type="Sub-task",
310+
parent_id="TEST-123",
311+
)
312+
created_subtask = self.client.create_subtask(subtask_data.model_dump())
300313

301-
self.assertIsNotNone(created_subtask)
302-
self.assertEqual(created_subtask["key"], "TEST-124")
303-
self.mock_jira_instance.issue_create.assert_called_once()
314+
self.assertIsNotNone(created_subtask)
315+
self.assertEqual(created_subtask["key"], "TEST-124")
316+
mock_jira_instance.issue_create.assert_called_once()
304317

305318

306319
if __name__ == "__main__":

tests/test_multi_issue_upload_with_subtasks.py

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,19 @@
11
import unittest
2-
from unittest.mock import mock_open, patch
3-
from src import multi_issue_upload_with_subtasks
2+
from unittest.mock import mock_open, patch, Mock
3+
import sys
4+
import os
5+
6+
# Add src to path without importing pydantic modules
7+
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))
8+
9+
# Mock pydantic before importing
10+
with patch.dict('sys.modules', {
11+
'pydantic': Mock(),
12+
'pydantic.BaseModel': Mock(),
13+
'pydantic.Field': Mock(),
14+
'pydantic.field_validator': Mock(),
15+
}):
16+
from multi_issue_upload_with_subtasks import read_csv, create_jira_issue, create_jira_subtask
417

518

619
class TestJiraScript(unittest.TestCase):
@@ -12,45 +25,41 @@ class TestJiraScript(unittest.TestCase):
1225
read_data="Project Key,Summary,Description,Issue Type\nTest,Ticket 1,Description 1,Task",
1326
)
1427
def test_read_csv(self, mock_open_instance):
15-
rows = multi_issue_upload_with_subtasks.read_csv("dummy.csv")
28+
rows = read_csv("dummy.csv")
1629
self.assertEqual(len(rows), 1)
1730
self.assertEqual(rows[0]["Project Key"], "Test")
1831
# ... more assertions based on your CSV structure
1932

2033
# Test for create_jira_issue function
21-
@patch.object(
22-
multi_issue_upload_with_subtasks.jira,
23-
"issue_create",
24-
return_value={"key": "TEST-123", "id": "001"},
25-
)
26-
def test_create_jira_issue(self, mock_issue_create):
34+
@patch('multi_issue_upload_with_subtasks.jira')
35+
def test_create_jira_issue(self, mock_jira):
36+
mock_jira.issue_create.return_value = {"key": "TEST-123", "id": "001"}
37+
2738
issue_data = {
2839
"project": {"key": "Test"},
2940
"summary": "Ticket 1",
3041
"description": "Description 1",
3142
"issuetype": {"name": "Task"},
3243
}
33-
response = multi_issue_upload_with_subtasks.create_jira_issue(issue_data)
34-
mock_issue_create.assert_called_once_with(fields=issue_data)
44+
response = create_jira_issue(issue_data)
45+
mock_jira.issue_create.assert_called_once_with(fields=issue_data)
3546
self.assertEqual(response["key"], "TEST-123")
3647
# ... more assertions if needed
3748

3849
# Test for create_jira_subtask function (similar to the one above)
39-
@patch.object(
40-
multi_issue_upload_with_subtasks.jira,
41-
"issue_create",
42-
return_value={"key": "TEST-124", "id": "002"},
43-
)
44-
def test_create_jira_subtask(self, mock_issue_create):
50+
@patch('multi_issue_upload_with_subtasks.jira')
51+
def test_create_jira_subtask(self, mock_jira):
52+
mock_jira.issue_create.return_value = {"key": "TEST-124", "id": "002"}
53+
4554
subtask_data = {
4655
"project": {"key": "Test"},
4756
"summary": "Subtask 1",
4857
"description": "Subtask Description 1",
4958
"issuetype": {"name": "Sub-task"},
5059
"parent": {"id": "001"},
5160
}
52-
response = multi_issue_upload_with_subtasks.create_jira_subtask(subtask_data)
53-
mock_issue_create.assert_called_once_with(fields=subtask_data)
61+
response = create_jira_subtask(subtask_data)
62+
mock_jira.issue_create.assert_called_once_with(fields=subtask_data)
5463
self.assertEqual(response["key"], "TEST-124")
5564
# ... more assertions if needed
5665

0 commit comments

Comments
 (0)