Skip to content

Commit

Permalink
Improve unittest coverage
Browse files Browse the repository at this point in the history
  • Loading branch information
yihong1120 committed Dec 24, 2024
1 parent dea495d commit 2cf9ce1
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 48 deletions.
78 changes: 58 additions & 20 deletions tests/examples/YOLO_evaluation/evaluate_sahi_yolo_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,26 +29,29 @@ def tearDown(self) -> None:
del self.evaluator

@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.'
'AutoDetectionModel.from_pretrained',
'examples.YOLO_evaluation.evaluate_sahi_yolo.COCOeval',
)
@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.'
'get_sliced_prediction',
'examples.YOLO_evaluation.evaluate_sahi_yolo.COCO',
)
@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.'
'Coco.from_coco_dict_or_path',
)
@patch('examples.YOLO_evaluation.evaluate_sahi_yolo.COCO')
@patch('examples.YOLO_evaluation.evaluate_sahi_yolo.COCOeval')
@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.get_sliced_prediction',
)
@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.'
'AutoDetectionModel.from_pretrained',
)
def test_evaluate(
self,
mock_cocoeval: MagicMock,
mock_coco: MagicMock,
mock_coco_from_path: MagicMock,
mock_get_sliced_prediction: MagicMock,
mock_auto_model: MagicMock,
mock_get_sliced_prediction: MagicMock,
mock_coco_from_path: MagicMock,
mock_coco: MagicMock,
mock_cocoeval: MagicMock,
) -> None:
"""
Test the evaluate method for computing COCO metrics.
Expand All @@ -59,10 +62,33 @@ def test_evaluate(

# Mock COCO annotations and evaluation
mock_coco_instance: MagicMock = MagicMock()

# Define mock categories with specific names and ids
mock_category1 = MagicMock()
mock_category1.name = 'Hardhat'
mock_category1.id = 1

mock_category2 = MagicMock()
mock_category2.name = 'Helmet'
mock_category2.id = 2

mock_coco_instance.categories = [mock_category1, mock_category2]

# Define mock images with specific ids and file names
mock_image1 = MagicMock()
mock_image1.id = 101
mock_image1.file_name = 'image1.jpg'

mock_image2 = MagicMock()
mock_image2.id = 102
mock_image2.file_name = 'image2.jpg'

mock_coco_instance.images = [mock_image1, mock_image2]

mock_coco.return_value = mock_coco_instance

mock_coco_from_instance: MagicMock = MagicMock()
mock_coco_from_path.return_value = mock_coco_from_instance
# Mock the Coco.from_coco_dict_or_path to return the mock_coco_instance
mock_coco_from_path.return_value = mock_coco_instance

mock_eval_instance: MagicMock = MagicMock()
# Simulate the precision and recall values
Expand All @@ -72,13 +98,26 @@ def test_evaluate(
}
mock_cocoeval.return_value = mock_eval_instance

# Mock the predictions
# Mock the predictions with specific category names
mock_pred1 = MagicMock()
mock_pred1.category.name = 'Hardhat'
mock_pred1.bbox.minx = 10
mock_pred1.bbox.miny = 20
mock_pred1.bbox.maxx = 110
mock_pred1.bbox.maxy = 220
mock_pred1.score.value = 0.9

mock_pred2 = MagicMock()
mock_pred2.category.name = 'Helmet'
mock_pred2.bbox.minx = 15
mock_pred2.bbox.miny = 25
mock_pred2.bbox.maxx = 115
mock_pred2.bbox.maxy = 225
mock_pred2.score.value = 0.85

mock_get_sliced_prediction.return_value.object_prediction_list = [
MagicMock(
category=MagicMock(name='Hardhat'),
bbox=MagicMock(minx=10, miny=20, maxx=110, maxy=220),
score=MagicMock(value=0.9),
),
mock_pred1,
mock_pred2,
]

# Run the evaluation
Expand All @@ -104,8 +143,7 @@ def test_evaluate(
self.assertEqual(metrics, expected_metrics)

@patch(
'examples.YOLO_evaluation.evaluate_sahi_yolo.'
'COCOEvaluator.evaluate',
'examples.YOLO_evaluation.evaluate_sahi_yolo.COCOEvaluator.evaluate',
)
@patch(
'argparse.ArgumentParser.parse_args', return_value=argparse.Namespace(
Expand Down
39 changes: 20 additions & 19 deletions tests/examples/line_chatbot/line_bot_test.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from __future__ import annotations

import json
import unittest
from unittest.mock import patch

Expand Down Expand Up @@ -45,26 +46,26 @@ def test_callback_ok(self) -> None:
"""
# Fake signature and body
fake_signature: str = 'fake_signature'
fake_body: str = """{
"events": [
fake_body: dict = {
'events': [
{
"replyToken": "reply_token",
"type": "message",
"message": {
"type": "text",
"text": "Hello"
}
}
]
}"""
'replyToken': 'reply_token',
'type': 'message',
'message': {
'type': 'text',
'text': 'Hello',
},
},
],
}

# Mock handler.handle to simulate no error
self.mock_handler_handle.return_value = None

# Send a POST request to the webhook endpoint
response = self.client.post(
'/webhook',
data=fake_body,
json=fake_body,
headers={'X-Line-Signature': fake_signature},
)

Expand All @@ -75,20 +76,20 @@ def test_callback_ok(self) -> None:
# Ensure the handler.handle method
# was called once with correct arguments
self.mock_handler_handle.assert_called_once_with(
fake_body, fake_signature,
json.dumps(fake_body), fake_signature,
)

def test_callback_missing_signature(self) -> None:
"""
Test that the webhook endpoint returns 400 if no signature is provided.
"""
# Fake body without signature
fake_body: str = '{"events":[]}'
fake_body: dict = {'events': []}

# Send a POST request without a signature header
response = self.client.post(
'/webhook',
data=fake_body,
json=fake_body,
headers={}, # Missing X-Line-Signature
)

Expand All @@ -102,15 +103,15 @@ def test_callback_invalid_signature(self) -> None:
from linebot.exceptions import InvalidSignatureError

fake_signature: str = 'fake_signature'
fake_body: str = '{"events":[]}'
fake_body: dict = {'events': []}

# Simulate an InvalidSignatureError being raised
self.mock_handler_handle.side_effect = InvalidSignatureError

# Send a POST request with an invalid signature
response = self.client.post(
'/webhook',
data=fake_body,
json=fake_body,
headers={'X-Line-Signature': fake_signature},
)

Expand All @@ -123,15 +124,15 @@ def test_callback_internal_server_error(self) -> None:
for unexpected server errors.
"""
fake_signature: str = 'fake_signature'
fake_body: str = '{"events":[]}'
fake_body: dict = {'events': []}

# Simulate a generic exception being raised
self.mock_handler_handle.side_effect = Exception('Some error')

# Send a POST request
response = self.client.post(
'/webhook',
data=fake_body,
json=fake_body,
headers={'X-Line-Signature': fake_signature},
)

Expand Down
35 changes: 26 additions & 9 deletions tests/src/stream_capture_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import sys
import time
import unittest
from typing import cast
from unittest import IsolatedAsyncioTestCase
from unittest.mock import AsyncMock
from unittest.mock import MagicMock
Expand Down Expand Up @@ -155,11 +156,13 @@ async def mock_generic():
# First frame: Validate first frame
# from `capture_generic_frames`.
generic_frame_0, ts_0 = await gen.__anext__()
generic_frame_0 = cast(MagicMock, generic_frame_0)
self.assertEqual(generic_frame_0.name, 'GenericFrame0')

# Second frame: Validate subsequent
# frame from `generic_frames`.
generic_frame_1, ts_1 = await gen.__anext__()
generic_frame_1 = cast(MagicMock, generic_frame_1)
self.assertEqual(generic_frame_1.name, 'GenericFrame1')

# After `generic_frames` iteration completes,
Expand Down Expand Up @@ -426,34 +429,48 @@ def test_update_capture_interval(self) -> None:
self.assertEqual(self.stream_capture.capture_interval, 20)

@patch('argparse.ArgumentParser.parse_args')
@patch('builtins.print')
@patch('gc.collect')
async def test_main_function(
self,
mock_gc_collect: MagicMock,
mock_print: MagicMock,
mock_parse_args: MagicMock,
) -> None:
"""
Test that the main function correctly initialises
and executes StreamCapture.
Args:
mock_parse_args (MagicMock):
Mock for argparse.ArgumentParser.parse_args.
mock_gc_collect (MagicMock): Mock for gc.collect function.
mock_print (MagicMock): Mock for print function.
mock_parse_args (MagicMock): Mock for
argparse.ArgumentParser.parse_args.
"""
# Mock command line argument parsing
# Mock parse_args method to return a stream URL
mock_parse_args.return_value = argparse.Namespace(
url='test_stream_url',
)

# Mock command line argument parsing
mock_capture_instance = MagicMock()
with patch(
'src.stream_capture.StreamCapture',
return_value=mock_capture_instance,
# Mock frame and timestamp
mock_frame = np.zeros((480, 640, 3), dtype=np.uint8)
mock_timestamp = 1234567890.0

async def mock_execute_capture(self):
yield mock_frame, mock_timestamp

# Execute main function and verify print and gc.collect calls
with patch.object(
StreamCapture, 'execute_capture', mock_execute_capture,
):
with patch.object(
sys, 'argv', ['stream_capture.py', '--url', 'test_stream_url'],
):
await stream_capture_main()
mock_capture_instance.execute_capture.assert_called_once()

# Verify print and gc.collect calls
mock_print.assert_any_call(f"Frame at {mock_timestamp} displayed")
mock_gc_collect.assert_called()

@patch('cv2.VideoCapture')
@patch('time.sleep', return_value=None)
Expand Down

0 comments on commit 2cf9ce1

Please sign in to comment.