-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Dev javi/add unit tests for twitter services (#8)
* Code refactor to implement unit testing * Udpate comments. * Update content. * Content update.
- Loading branch information
Showing
7 changed files
with
230 additions
and
115 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
34 changes: 34 additions & 0 deletions
34
src/weather-station/services/twitter_create_post_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import tweepy | ||
|
||
def create_tweet( | ||
api_key, | ||
api_secret, | ||
access_token, | ||
access_secret, | ||
tweet_content | ||
) -> str: | ||
|
||
created_tweet_url = "NONE" | ||
|
||
try: | ||
|
||
# Create X (Twitter) client. | ||
client = tweepy.Client( | ||
consumer_key=api_key, | ||
consumer_secret=api_secret, | ||
access_token=access_token, | ||
access_token_secret=access_secret | ||
) | ||
|
||
response = client.create_tweet( | ||
text=tweet_content | ||
) | ||
|
||
created_tweet_url = f"https://twitter.com/user/status/{response.data['id']}" | ||
|
||
return created_tweet_url | ||
|
||
except Exception as error: | ||
|
||
print({'error': f"Create tweet HTTP status code: {error}"}) | ||
return created_tweet_url |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,97 +1,58 @@ | ||
import tweepy | ||
from typing import Callable, Optional | ||
from typing import Callable | ||
|
||
from model.report.weather_day_summary_report import WeatherDaySummaryReport | ||
|
||
def trasnlate_to_spanish_uv_risk(uv_risk:str) -> str: | ||
|
||
value = "_" | ||
|
||
match uv_risk: | ||
case "Low": | ||
value = "Bajo" | ||
case "Medium": | ||
value = "Medio" | ||
case "High": | ||
value = "Alto" | ||
case "Very high": | ||
value = "Muy alto" | ||
case "Extremely high": | ||
value = "Extremo" | ||
case "Very high": | ||
value = "Muy alto" | ||
case _: | ||
value = "NONE" | ||
|
||
return value | ||
def translate_to_spanish_uv_risk(uv_risk: str) -> str: | ||
translation = { | ||
"Low": "Bajo", | ||
"Medium": "Medio", | ||
"High": "Alto", | ||
"Very high": "Muy alto", | ||
"Extremely high": "Extremo" | ||
} | ||
return translation.get(uv_risk, "NONE") | ||
|
||
def build_tweet(weather_day_summary_report: WeatherDaySummaryReport) -> str: | ||
|
||
date_str = weather_day_summary_report.Date | ||
|
||
temperature_max = weather_day_summary_report.TemperatureHigh | ||
temperature_low = weather_day_summary_report.TemperatureLow | ||
temperature_avg = weather_day_summary_report.TemperatureAvg | ||
precipitation_total = weather_day_summary_report.PrecipitationTotal | ||
wind_speed_avg = weather_day_summary_report.WindSpeedAvg | ||
wind_direction_avg = weather_day_summary_report.WindDirectionAvg | ||
wind_gust_high = weather_day_summary_report.WindGustHigh | ||
uv_high = weather_day_summary_report.UvIndexHigh | ||
uv_risk = weather_day_summary_report.UvHighRisk | ||
solar_radiation_high = weather_day_summary_report.SolarRadiationHigh | ||
|
||
msg = ( | ||
return ( | ||
f"¡Buenos días Castrocontrigo!\n" | ||
f"Resumen de ayer 📅 {date_str}:\n\n" | ||
f"🌡️ Temp. (ºC): Max. {temperature_max} | Min. {temperature_low} | Media. {temperature_avg}\n" | ||
f"💧 Lluvia: {precipitation_total} L/m²\n" | ||
f"💨 Viento medio: {wind_speed_avg} km/h | Dir. media: {wind_direction_avg}\n" | ||
f"🌀 Racha viento max.: {wind_gust_high} km/h\n" | ||
f"☀️ Índice UV max.: {uv_high} ({trasnlate_to_spanish_uv_risk(uv_risk)})\n" | ||
f"😎 Radiación solar max.: {solar_radiation_high} W/m²" | ||
f"Resumen de ayer 📅 {weather_day_summary_report.Date}:\n\n" | ||
f"🌡️ Temp. (ºC): Max. {weather_day_summary_report.TemperatureHigh} | " | ||
f"Min. {weather_day_summary_report.TemperatureLow} | " | ||
f"Media. {weather_day_summary_report.TemperatureAvg}\n" | ||
f"💧 Lluvia: {weather_day_summary_report.PrecipitationTotal} L/m²\n" | ||
f"💨 Viento medio: {weather_day_summary_report.WindSpeedAvg} km/h | " | ||
f"Dir. media: {weather_day_summary_report.WindDirectionAvg}\n" | ||
f"🌀 Racha viento max.: {weather_day_summary_report.WindGustHigh} km/h\n" | ||
f"☀️ Índice UV max.: {weather_day_summary_report.UvIndexHigh} " | ||
f"({translate_to_spanish_uv_risk(weather_day_summary_report.UvHighRisk)})\n" | ||
f"😎 Radiación solar max.: {weather_day_summary_report.SolarRadiationHigh} W/m²" | ||
) | ||
|
||
return msg | ||
|
||
def create_tweet( | ||
api_key_for_x:str, | ||
api_key_secret_for_x:str, | ||
access_token_for_x:str, | ||
access_secret_token_for_x:str, | ||
tweet_content:str | ||
) -> str: | ||
|
||
created_tweet_url = "NONE" | ||
|
||
try: | ||
|
||
# Create X (Twitter) client. | ||
client = tweepy.Client( | ||
consumer_key=api_key_for_x, | ||
consumer_secret=api_key_secret_for_x, | ||
access_token=access_token_for_x, | ||
access_token_secret=access_secret_token_for_x | ||
) | ||
|
||
response = client.create_tweet( | ||
text=tweet_content | ||
) | ||
|
||
created_tweet_url = f"https://twitter.com/user/status/{response.data['id']}" | ||
|
||
return created_tweet_url | ||
|
||
except Exception as error: | ||
|
||
print({'error': f"Create tweet HTTP status code: {error}"}) | ||
return created_tweet_url | ||
|
||
class TwitterService: | ||
|
||
def __init__( | ||
self, | ||
create_tweet: Callable[[str, str, str, str, str], str], | ||
build_tweet: Callable[[WeatherDaySummaryReport], str] | ||
): | ||
): | ||
self.build_tweet = build_tweet | ||
self.create_tweet = create_tweet | ||
self.create_tweet = create_tweet | ||
|
||
def post_weather_report( | ||
self, | ||
api_key: str, | ||
api_secret: str, | ||
access_token: str, | ||
access_secret: str, | ||
weather_report: WeatherDaySummaryReport | ||
) -> str: | ||
|
||
tweet_content = self.build_tweet(weather_report) | ||
|
||
return self.create_tweet( | ||
api_key, | ||
api_secret, | ||
access_token, | ||
access_secret, | ||
tweet_content | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
94 changes: 94 additions & 0 deletions
94
src/weather-station/test/unit_tests/test_twitter_service.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import unittest | ||
from unittest.mock import MagicMock | ||
from model.report.weather_day_summary_report import WeatherDaySummaryReport | ||
from services.twitter_service import TwitterService, build_tweet, translate_to_spanish_uv_risk | ||
|
||
class TestTwitterService(unittest.TestCase): | ||
|
||
def setUp(self): | ||
"""Configure mocks""" | ||
self.mock_create_tweet = MagicMock(return_value="https://twitter.com/user/status/123456789") | ||
|
||
self.weather_report = WeatherDaySummaryReport( | ||
Date="2024-02-03", | ||
TemperatureHigh=14.4, | ||
TemperatureAvg=7.7, | ||
TemperatureLow=2.2, | ||
DewPointHigh=6.4, | ||
DewPointLow=-0.8, | ||
DewPointAvg=2.7, | ||
HumidityHigh=99.0, | ||
HumidityLow=40.0, | ||
HumidityAvg=72.7, | ||
PrecipitationTotal=15.6, | ||
PressureMax=1008.13, | ||
PressureMin=1002.37, | ||
WindSpeedHigh=19.8, | ||
WindSpeedAvg=4.6, | ||
WindGustHigh=25.4, | ||
WindGustAvg=6.3, | ||
WindDirectionAvg="WNW", | ||
UvHighRisk="Medium", | ||
UvIndexHigh=5.0, | ||
SolarRadiationHigh=460.1 | ||
) | ||
|
||
self.twitter_service = TwitterService( | ||
create_tweet=self.mock_create_tweet, | ||
build_tweet=build_tweet | ||
) | ||
|
||
def test_build_tweet_generates_correct_message(self): | ||
|
||
# Arrange | ||
expected_values = [ | ||
f"Resumen de ayer 📅 {self.weather_report.Date}", | ||
f"🌡️ Temp. (ºC): Max. {self.weather_report.TemperatureHigh} | " | ||
f"Min. {self.weather_report.TemperatureLow} | " | ||
f"Media. {self.weather_report.TemperatureAvg}", | ||
f"💧 Lluvia: {self.weather_report.PrecipitationTotal} L/m²", | ||
f"💨 Viento medio: {self.weather_report.WindSpeedAvg} km/h | " | ||
f"Dir. media: {self.weather_report.WindDirectionAvg}", | ||
f"🌀 Racha viento max.: {self.weather_report.WindGustHigh} km/h", | ||
f"☀️ Índice UV max.: {self.weather_report.UvIndexHigh} " | ||
f"({translate_to_spanish_uv_risk(self.weather_report.UvHighRisk)})", | ||
f"😎 Radiación solar max.: {self.weather_report.SolarRadiationHigh} W/m²" | ||
] | ||
|
||
# Act | ||
tweet = build_tweet(self.weather_report) | ||
|
||
# Assert | ||
for value in expected_values: | ||
with self.subTest(value=value): | ||
self.assertIn(value, tweet) | ||
|
||
def test_post_weather_report_calls_create_tweet_correctly(self): | ||
"""Act: Call `post_weather_report`. Assert: Validate call to `create_tweet`.""" | ||
|
||
tweet_url = self.twitter_service.post_weather_report( | ||
"API_KEY_FAKE", | ||
"API_SECRET_FAKE", | ||
"ACCESS_TOKEN_FAKE", | ||
"ACCESS_SECRET_FAKE", self.weather_report | ||
) | ||
|
||
self.mock_create_tweet.assert_called_once_with( | ||
"API_KEY_FAKE", | ||
"API_SECRET_FAKE", | ||
"ACCESS_TOKEN_FAKE", | ||
"ACCESS_SECRET_FAKE", | ||
build_tweet(self.weather_report) | ||
) | ||
|
||
self.assertEqual(tweet_url, "https://twitter.com/user/status/123456789") | ||
|
||
def test_translate_to_spanish_uv_risk(self): | ||
"""Act & Assert: Testing translation of different UV levels.""" | ||
|
||
self.assertEqual(translate_to_spanish_uv_risk("Low"), "Bajo") | ||
self.assertEqual(translate_to_spanish_uv_risk("Medium"), "Medio") | ||
self.assertEqual(translate_to_spanish_uv_risk("High"), "Alto") | ||
self.assertEqual(translate_to_spanish_uv_risk("Very high"), "Muy alto") | ||
self.assertEqual(translate_to_spanish_uv_risk("Extremely high"), "Extremo") | ||
self.assertEqual(translate_to_spanish_uv_risk("Unknown"), "NONE") |
Oops, something went wrong.