The report should include the project's background and motivation and a brief overview of related and similar work, with at least 3 references. This formal report will be a culmination of previous reports submitted and should include a detailed description of the implemented system, including what it does, how it works, and how it is used. The report should address all the feedback provided in previous submissions. The report should also detail the group’s accomplishments and reflect on their experience.
Final Report Outline:
- Introduction – Brief summary of your project, context and motivation
- Process Overview – brief description of your approach, tools and artifacts used, including summary of individual contributions
- Requirements Specification – summary of functional and non-functional requirements
- Project Design – architecture and implementation of your project and how it works
- Project Evaluation: Testing strategy, Test Plan and Results, Validation
- Design and Alternate Designs – changes made to the source code due to testing results
- Development History: Project timeline
- Discussion: Lessons learned, design strengths, limitations and suggestions for future improvement
- Conclusion
- Acknowledgement (optional)
- References
- Appendix
- System specification: technical specifications, minimum hardware requirements of the project implemented
- User Guide
- Other appendices (optional)
Guidelines for the format and submission of the paper are as follows:
- The paper should be 15-20 pages in length. (This minimum and maximum length should not include the title page, appendix, separate figures and tables, or the list of references);
- The paper should include a cover page containing the project's title and the names of project team members. All team members should submit the same document to the assignment submission area.
- Careful attention should be given to source citations, and a proper listing of references.
- The paper should be well formatted and well organized with proper formatting of all graphs, images, tables etc.
weather_app/pom.xml
4.0.0 org.springframework.boot spring-boot-starter-parent 3.3.1 com.service weather 0.0.1-SNAPSHOT weather Weather website 17 org.springframework.boot spring-boot-starter-web com.h2database h2 runtime org.springframework.boot spring-boot-starter-test test jakarta.persistence jakarta.persistence-api 3.1.0 org.mockito mockito-core test org.mockito mockito-junit-jupiter test org.springframework.boot spring-boot-starter-data-jpa org.springframework.boot spring-boot-maven-plugin
weather_app/src/main/java/com/service/weather/controller/WeatherController.java
weather_app/src/main/java/com/service/weather/controller/WeatherController.java
package com . service . weather . controller ;
import com . service . weather . model . WeatherRecord ;
import com . service . weather . service . WeatherService ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . web . bind . annotation . * ;
/**
* The WeatherController class handles HTTP requests related to weather data.
* It provides an endpoint to fetch weather information based on a given zip code.
*/
@ RestController
@ RequestMapping ( "/api/weather" )
public class WeatherController {
@ Autowired
private WeatherService weatherService ;
@ GetMapping
public WeatherRecord getWeatherByZipCode ( @ RequestParam String zipCode ) {
return weatherService . getWeatherByZipCode ( zipCode );
}
}
weather_app/src/main/java/com/service/weather/controller/ZipCodeController.java
weather_app/src/main/java/com/service/weather/controller/ZipCodeController.java
package com . service . weather . controller ;
import com . service . weather . model . ZipCode ;
import com . service . weather . service . ZipCodeService ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . web . bind . annotation . * ;
import java . util . List ;
/**
* The ZipCodeController class handles HTTP requests related to zip codes.
* It provides endpoints to fetch all zip codes, add a new zip code, and remove an existing zip code.
*/
@ RestController
@ RequestMapping ( "/api/zipcodes" )
public class ZipCodeController {
@ Autowired
private ZipCodeService zipCodeService ;
@ GetMapping
public List < ZipCode > getAllZipCodes () {
return zipCodeService . getAllZipCodes ();
}
@ PostMapping
public ZipCode addZipCode ( @ RequestBody ZipCode zipCode ) {
return zipCodeService . addZipCode ( zipCode );
}
@ DeleteMapping ( "/{id}" )
public void removeZipCode ( @ PathVariable Long id ) {
zipCodeService . removeZipCode ( id );
}
}
weather_app/src/main/java/com/service/weather/model/OpenWeatherMapResponse.java
weather_app/src/main/java/com/service/weather/model/OpenWeatherMapResponse.java
package com . service . weather . model ;
import com . fasterxml . jackson . annotation . JsonIgnoreProperties ;
import com . fasterxml . jackson . annotation . JsonProperty ;
import java . util . List ;
/**
* The OpenWeatherMapResponse class represents the response structure from the OpenWeatherMap API.
*/
@ JsonIgnoreProperties ( ignoreUnknown = true )
public class OpenWeatherMapResponse {
private Main main ;
private Wind wind ;
private List < Weather > weather ;
private String name ;
public Main getMain () {
return main ;
}
public void setMain ( Main main ) {
this . main = main ;
}
public Wind getWind () {
return wind ;
}
public void setWind ( Wind wind ) {
this . wind = wind ;
}
public List < Weather > getWeather () {
return weather ;
}
public void setWeather ( List < Weather > weather ) {
this . weather = weather ;
}
public String getName () {
return name ;
}
public void setName ( String name ) {
this . name = name ;
}
@ JsonIgnoreProperties ( ignoreUnknown = true )
public static class Main {
private double temp ;
@ JsonProperty ( "feels_like" )
private double feels_like ;
private double temp_min ;
private double temp_max ;
private int humidity ;
public double getTemp () {
return temp ;
}
public void setTemp ( double temp ) {
this . temp = temp ;
}
public double getFeels_like () {
return feels_like ;
}
public void setFeels_like ( double feelsLike ) {
this . feels_like = feelsLike ;
}
public double getTemp_min () {
return temp_min ;
}
public void setTemp_min ( double temp_min ) {
this . temp_min = temp_min ;
}
public double getTemp_max () {
return temp_max ;
}
public void setTemp_max ( double temp_max ) {
this . temp_max = temp_max ;
}
public int getHumidity () {
return humidity ;
}
public void setHumidity ( int humidity ) {
this . humidity = humidity ;
}
}
@ JsonIgnoreProperties ( ignoreUnknown = true )
public static class Wind {
private double speed ;
// Getters and setters
public double getSpeed () {
return speed ;
}
public void setSpeed ( double speed ) {
this . speed = speed ;
}
}
@ JsonIgnoreProperties ( ignoreUnknown = true )
public static class Weather {
private int id ;
private String icon ;
// Getters and setters
public int getId () {
return id ;
}
public void setId ( int id ) {
this . id = id ;
}
public String getIcon () {
return icon ;
}
public void setIcon ( String icon ) {
this . icon = icon ;
}
}
}
weather_app/src/main/java/com/service/weather/model/WeatherRecord.java
weather_app/src/main/java/com/service/weather/model/WeatherRecord.java
package com . service . weather . model ;
import jakarta . persistence . Entity ;
import jakarta . persistence . GeneratedValue ;
import jakarta . persistence . GenerationType ;
import jakarta . persistence . Id ;
/**
* The WeatherRecord class represents a record of weather data.
*/
@ Entity
public class WeatherRecord {
@ Id
@ GeneratedValue ( strategy = GenerationType . AUTO )
private Long id ;
private String zipCode ;
private double temperature ;
private double feelsLike ;
private double tempMin ;
private double tempMax ;
private int humidity ;
private double windSpeed ;
private String city ;
private String icon ;
private int conditionCode ;
public WeatherRecord () {}
public WeatherRecord ( String zipCode , double temperature , double feelsLike , double tempMin , double tempMax , int humidity , double windSpeed , String city , String icon , int conditionCode ) {
this . zipCode = zipCode ;
this . temperature = temperature ;
this . feelsLike = feelsLike ;
this . tempMin = tempMin ;
this . tempMax = tempMax ;
this . humidity = humidity ;
this . windSpeed = windSpeed ;
this . city = city ;
this . icon = icon ;
this . conditionCode = conditionCode ;
}
public Long getId () {
return id ;
}
public void setId ( Long id ) {
this . id = id ;
}
public String getZipCode () {
return zipCode ;
}
public void setZipCode ( String zipCode ) {
this . zipCode = zipCode ;
}
public double getTemperature () {
return temperature ;
}
public void setTemperature ( double temperature ) {
this . temperature = temperature ;
}
public double getFeelsLike () {
return feelsLike ;
}
public void setFeelsLike ( double feelsLike ) {
this . feelsLike = feelsLike ;
}
public double getTempMin () {
return tempMin ;
}
public void setTempMin ( double tempMin ) {
this . tempMin = tempMin ;
}
public double getTempMax () {
return tempMax ;
}
public void setTempMax ( double tempMax ) {
this . tempMax = tempMax ;
}
public int getHumidity () {
return humidity ;
}
public void setHumidity ( int humidity ) {
this . humidity = humidity ;
}
public double getWindSpeed () {
return windSpeed ;
}
public void setWindSpeed ( double windSpeed ) {
this . windSpeed = windSpeed ;
}
public String getCity () {
return city ;
}
public void setCity ( String city ) {
this . city = city ;
}
public String getIcon () {
return icon ;
}
public void setIcon ( String icon ) {
this . icon = icon ;
}
public int getConditionCode () {
return conditionCode ;
}
public void setConditionCode ( int conditionCode ) {
this . conditionCode = conditionCode ;
}
}
weather_app/src/main/java/com/service/weather/model/ZipCode.java
weather_app/src/main/java/com/service/weather/model/ZipCode.java
package com . service . weather . model ;
import jakarta . persistence . Entity ;
import jakarta . persistence . GeneratedValue ;
import jakarta . persistence . GenerationType ;
import jakarta . persistence . Id ;
/**
* The ZipCode class represents a record of Zipcode data.
*/
@ Entity
public class ZipCode {
@ Id
@ GeneratedValue ( strategy = GenerationType . AUTO )
private Long id ;
private String city ;
private String zipCode ;
public ZipCode () {
}
public ZipCode ( Long id , String city , String zipCode ) {
this . id = id ;
this . city = city ;
this . zipCode = zipCode ;
}
public Long getId () {
return id ;
}
public void setId ( Long id ) {
this . id = id ;
}
public String getCity () {
return city ;
}
public void setCity ( String city ) {
this . city = city ;
}
public String getZipCode () {
return zipCode ;
}
public void setZipCode ( String zipCode ) {
this . zipCode = zipCode ;
}
}
weather_app/src/main/java/com/service/weather/repository/ZipCodeRepository.java
weather_app/src/main/java/com/service/weather/repository/ZipCodeRepository.java
package com . service . weather . repository ;
import com . service . weather . model . ZipCode ;
import org . springframework . data . jpa . repository . JpaRepository ;
import org . springframework . stereotype . Repository ;
@ Repository
public interface ZipCodeRepository extends JpaRepository < ZipCode , Long > {
}
weather_app/src/main/java/com/service/weather/service/DataInitializer.java
weather_app/src/main/java/com/service/weather/service/DataInitializer.java
package com . service . weather . service ;
import com . service . weather . model . ZipCode ;
import com . service . weather . repository . ZipCodeRepository ;
import jakarta . annotation . PostConstruct ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . stereotype . Service ;
/**
* The DataInitializer class is responsible for initializing the database with some default zip codes.
* It checks if the database is empty and, if so, adds a predefined set of zip codes.
*/
@ Service
public class DataInitializer {
@ Autowired
private ZipCodeRepository zipCodeRepository ;
@ PostConstruct
public void init () {
// Check if zip codes are already in the database
if ( zipCodeRepository . count () == 0 ) {
// Add initial zip codes
zipCodeRepository . save ( new ZipCode ( null , "New York" , "10001" ));
zipCodeRepository . save ( new ZipCode ( null , "San Francisco" , "94114" ));
zipCodeRepository . save ( new ZipCode ( null , "Plano" , "75075" ));
}
}
}
weather_app/src/main/java/com/service/weather/service/WeatherService.java
weather_app/src/main/java/com/service/weather/service/WeatherService.java
package com . service . weather . service ;
import com . service . weather . model . OpenWeatherMapResponse ;
import com . service . weather . model . WeatherRecord ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . beans . factory . annotation . Value ;
import org . springframework . stereotype . Service ;
import org . springframework . web . client . RestTemplate ;
/**
* The WeatherService class is responsible for fetching and processing weather data from the OpenWeatherMap API.
* It retrieves weather information based on a provided zip code and converts the response into a WeatherRecord object.
*/
@ Service
public class WeatherService {
@ Autowired
private RestTemplate restTemplate ;
@ Value ( "${openweathermap.api.key}" )
private String apiKey ;
private final String BASE_URL = "http://api.openweathermap.org/data/2.5/weather" ;
private final String ICON_URL = "https://openweathermap.org/img/wn/" ;
/**
* Fetches weather data for a given zip code from the OpenWeatherMap API.
*
* @param zipCode the zip code for which to fetch the weather
* @return a WeatherRecord object containing the fetched weather data
*/
public WeatherRecord getWeatherByZipCode ( String zipCode ) {
String url = String . format ( "%s?zip=%s,us&units=imperial&appid=%s" , BASE_URL , zipCode , apiKey );
OpenWeatherMapResponse response = restTemplate . getForObject ( url , OpenWeatherMapResponse . class );
if ( response != null ) {
WeatherRecord record = new WeatherRecord ();
record . setZipCode ( zipCode );
record . setTemperature ( response . getMain (). getTemp ());
record . setFeelsLike ( response . getMain (). getFeels_like ());
record . setTempMin ( response . getMain (). getTemp_min ());
record . setTempMax ( response . getMain (). getTemp_max ());
record . setHumidity ( response . getMain (). getHumidity ());
record . setWindSpeed ( response . getWind (). getSpeed ());
record . setCity ( response . getName ());
String iconCode = response . getWeather (). get ( 0 ). getIcon ();
String iconUrl = String . format ( "%s%[email protected]" , ICON_URL , iconCode );
record . setIcon ( iconUrl );
record . setConditionCode ( response . getWeather (). get ( 0 ). getId ());
return record ;
} else {
throw new RuntimeException ( "Unable to fetch weather data" );
}
}
}
weather_app/src/main/java/com/service/weather/service/ZipCodeService.java
weather_app/src/main/java/com/service/weather/service/ZipCodeService.java
package com . service . weather . service ;
import com . service . weather . model . ZipCode ;
import com . service . weather . repository . ZipCodeRepository ;
import org . springframework . beans . factory . annotation . Autowired ;
import org . springframework . stereotype . Service ;
import java . util . List ;
/**
* The ZipCodeService class provides business logic for handling zip code operations.
* It interacts with the ZipCodeRepository to perform CRUD operations on zip code data.
*/
@ Service
public class ZipCodeService {
@ Autowired
private ZipCodeRepository zipCodeRepository ;
public List < ZipCode > getAllZipCodes () {
return zipCodeRepository . findAll ();
}
public ZipCode addZipCode ( ZipCode zipCode ) {
return zipCodeRepository . save ( zipCode );
}
public void removeZipCode ( Long id ) {
zipCodeRepository . deleteById ( id );
}
}
weather_app/src/main/java/com/service/weather/WeatherApplication.java
weather_app/src/main/java/com/service/weather/WeatherApplication.java
package com . service . weather ;
import org . springframework . boot . SpringApplication ;
import org . springframework . boot . autoconfigure . SpringBootApplication ;
import org . springframework . context . annotation . Bean ;
import org . springframework . context . annotation . ComponentScan ;
import org . springframework . web . client . RestTemplate ;
@ SpringBootApplication
@ ComponentScan ( basePackages = "com.service.weather" )
public class WeatherApplication {
public static void main ( String [] args ) {
SpringApplication . run ( WeatherApplication . class , args );
}
@ Bean
public RestTemplate restTemplate () {
return new RestTemplate ();
}
}
weather_app/src/main/resources/application.properties
server..port=8090 spring.application.name=weather # H2 Database Configuration spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password=password spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.jpa.database-platform=org.hibernate.dialect.H2Dialect # JPA Configuration spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true openweathermap.api.key=5f40dfe3704a02e2e7a64d58dcefc566
weather_app/src/main/resources/static/css/styles.css
body { font-family: 'Arial', sans-serif; margin: 0; padding: 0; display: flex; flex-direction: column; align-items: center; background: linear-gradient(to right, #6a11cb, #2575fc); color: #fff; height: 100vh; justify-content: space-between; } .container { width: 90%; max-width: 600px; padding: 20px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); } header { text-align: center; margin-bottom: 20px; } h1 { font-size: 2.5em; margin: 0; color: #fff; } h2 { margin-bottom: 10px; } form { display: flex; justify-content: center; margin-bottom: 20px; } input { padding: 10px; font-size: 16px; border: none; border-radius: 5px; margin-right: 10px; } button { padding: 10px 20px; font-size: 16px; cursor: pointer; border: none; border-radius: 5px; background-color: #2575fc; color: #fff; transition: background-color 0.3s ease; } button:hover { background-color: #6a11cb; } #weatherResult, #savedWeatherResults { font-size: 18px; color: #fff; } #zipCodeList { list-style: none; padding: 0; width: 100%; } #zipCodeList li { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; background: rgba(255, 255, 255, 0.2); padding: 10px; border-radius: 5px; } #zipCodeList li span { flex: 1; } .weather-container { display: flex; border: 2px solid #ccc; border-radius: 10px; padding: 20px; max-width: 800px; margin: 20px auto; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); background: rgba(255, 255, 255, 0.1); } .weather-header, .weather-details { flex: 1; margin: 10px; } .weather-header { display: flex; flex-direction: column; align-items: center; justify-content: center; border-right: 2px solid #ccc; padding-right: 20px; } .city-name { font-size: 1.5em; font-weight: bold; } .weather-icon { width: 50px; height: 50px; } .temperature { font-size: 2em; color: #f39c12; } .weather-details { background-color: #f2f2f2; padding: 10px; border-radius: 10px; display: flex; flex-direction: column; justify-content: center; color: #000; } .weather-details p { margin: 5px 0; } #zipCodeList li button { margin-left: 10px; padding: 5px 10px; border: none; border-radius: 5px; background-color: #ff4e50; color: #fff; cursor: pointer; transition: background-color 0.3s ease; } #zipCodeList li button:hover { background-color: #fc913a; } .scroll-container { display: flex; overflow-x: auto; padding: 10px 0; } #popularZipCodeList { display: flex; flex-direction: row; list-style: none; padding: 0; margin: 0; } #popularZipCodeList li { display: flex; flex-direction: column; align-items: center; justify-content: center; margin-right: 10px; background: rgba(255, 255, 255, 0.2); padding: 10px; border-radius: 5px; color: #fff; min-width: 100px; border: 1px solid #fff; } #popularZipCodeList li span { margin-bottom: 5px; } #popularZipCodeList li button { margin-top: 5px; padding: 5px 10px; border: none; border-radius: 5px; background-color: #ff4e50; color: #fff; cursor: pointer; transition: background-color 0.3s ease; } #popularZipCodeList li button:hover { background-color: #fc913a; }
weather_app/src/main/resources/static/index.html
Weather App
Search Weather by Zip Code
Get Weather
Add Zip Code to List
Add to List
Saved Zip Codes
Popular Weather Locations
© 2024 Weather App. All rights reserved.
weather_app/src/main/resources/static/js/script.js
document.addEventListener('DOMContentLoaded', function() { const weatherForm = document.getElementById('weatherForm'); const addZipForm = document.getElementById('addZipForm'); const zipCodeInput = document.getElementById('zipCode'); const addZipCodeInput = document.getElementById('addZipCode'); const weatherResult = document.getElementById('weatherResult'); const zipCodeList = document.getElementById('zipCodeList'); const savedWeatherResults = document.getElementById('savedWeatherResults'); const popularZipCodeList = document.getElementById('popularZipCodeList'); // Load stored zip codes and display weather for each loadStoredZipCodes(); // Load popular zip codes from the database loadZipCodesFromDB(); // Add event listener to the weather form for fetching weather data weatherForm.addEventListener('submit', function(event) { event.preventDefault(); const zipCode = zipCodeInput.value; fetchWeather(zipCode, weatherResult); }); // Add event listener to the add zip code form for adding a new zip code to the list addZipForm.addEventListener('submit', function(event) { event.preventDefault(); const zipCode = addZipCode.value; addZipCodeToList(zipCode); }); // Function to fetch weather data for a given zip code and display it function fetchWeather(zipCode, resultElement) { fetch(`/api/weather?zipCode=${zipCode}`) .then(response => { if (response.status === 500) { throw new Error('Invalid zip code'); } return response.json(); }) .then(data => { // Check for severe weather conditions if (isSevereWeather(data.conditionCode)) { alert(`Severe weather condition detected in ${data.city} (ZIP: ${zipCode}): ${getDescriptionForConditionCode(data.conditionCode)}`); } const weatherIcon = data.icon; const weatherInfo = ` <div id="weatherResult" class="weather-container"> <div class="weather-header"> <div class="city-name">${data.city}</div> <img src="${weatherIcon}" alt="Weather Icon" class="weather-icon" onerror="this.onerror=null; this.src='/images/default.png';"> <div class="temperature">${data.temperature} °F</div> </div> <div class="weather-details"> <p>Feels Like: ${data.feelsLike} °F</p> <p>Min Temp: ${data.tempMin} °F</p> <p>Max Temp: ${data.tempMax} °F</p> <p>Humidity: ${data.humidity} %</p> <p>Wind Speed: ${data.windSpeed} mph</p> </div> </div> `; resultElement.innerHTML = weatherInfo; }) .catch(error => { console.error('Error fetching weather data:', error); if (error.message === 'Invalid zip code') { alert('The provided zip code does not exist. Please enter a valid zip code.'); resultElement.innerHTML = 'Error: Invalid zip code'; } else { resultElement.innerHTML = 'Error fetching weather data'; } }); } // Function to check if the weather condition is severe based on the condition code function isSevereWeather(conditionCode) { const severeConditions = [200, 201, 202, 210, 211, 212, 221, 230, 231, 232, 502, 503, 504, 511, 522, 531, 601, 602, 622, 711, 731, 741, 751, 761, 762, 771, 781]; return severeConditions.includes(conditionCode); } // Function to get the description for a specific weather condition code function getDescriptionForConditionCode(conditionCode) { const conditionDescriptions = { 200: 'thunderstorm with light rain', 201: 'thunderstorm with rain', 202: 'thunderstorm with heavy rain', 210: 'light thunderstorm', 211: 'thunderstorm', 212: 'heavy thunderstorm', 221: 'ragged thunderstorm', 230: 'thunderstorm with light drizzle', 231: 'thunderstorm with drizzle', 232: 'thunderstorm with heavy drizzle', 502: 'heavy intensity rain', 503: 'very heavy rain', 504: 'extreme rain', 511: 'freezing rain', 522: 'heavy intensity shower rain', 531: 'ragged shower rain', 601: 'snow', 602: 'heavy snow', 622: 'heavy shower snow', 711: 'smoke', 731: 'sand/dust whirls', 741: 'fog', 751: 'sand', 761: 'dust', 762: 'volcanic ash', 771: 'squalls', 781: 'tornado' }; return conditionDescriptions[conditionCode] || 'Unknown severe condition'; } // Function to add a new zip code to the list and fetch its weather data function addZipCodeToList(zipCode) { const tempResultElement = document.createElement('div'); fetch(`/api/weather?zipCode=${zipCode}`) .then(response => { if (response.status === 500) { throw new Error('Invalid zip code'); } return response.json(); }) .then(data => { let storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; if (!storedZipCodes.includes(zipCode)) { storedZipCodes.push(zipCode); localStorage.setItem('zipCodes', JSON.stringify(storedZipCodes)); displayStoredZipCodes(storedZipCodes); fetchWeatherForSavedZipCode(zipCode); } }) .catch(error => { console.error('Error fetching weather data:', error); if (error.message === 'Invalid zip code') { alert('The provided zip code does not exist. Please enter a valid zip code.'); } }); } // Function to load stored zip codes from localStorage and display their weather data function loadStoredZipCodes() { const storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; displayStoredZipCodes(storedZipCodes); storedZipCodes.forEach(zipCode => fetchWeatherForSavedZipCode(zipCode)); } // Function to load popular zip codes from the database and display their weather data function loadZipCodesFromDB() { fetch('/api/zipcodes') .then(response => response.json()) .then(data => { const zipCodes = data.map(item => item.zipCode); displayPopularZipCodes(zipCodes); zipCodes.forEach(zipCode => fetchWeatherForPopularZipCode(zipCode)); }) .catch(error => console.error('Error fetching zip codes from DB:', error)); } // Function to display stored zip codes in the UI function displayStoredZipCodes(zipCodes) { zipCodeList.innerHTML = ''; zipCodes.forEach(zipCode => { const listItem = document.createElement('li'); const zipCodeText = document.createElement('span'); zipCodeText.textContent = zipCode; const resultElement = document.createElement('div'); resultElement.id = `weatherResult-${zipCode}`; resultElement.classList.add('weather-info'); const deleteButton = document.createElement('button'); deleteButton.textContent = 'Delete from list'; deleteButton.addEventListener('click', () => removeZipCode(zipCode)); listItem.appendChild(zipCodeText); listItem.appendChild(resultElement); listItem.appendChild(deleteButton); zipCodeList.appendChild(listItem); }); } // Function to display popular zip codes in the UI function displayPopularZipCodes(zipCodes) { popularZipCodeList.innerHTML = ''; zipCodes.forEach(zipCode => { const listItem = document.createElement('li'); const zipCodeText = document.createElement('span'); zipCodeText.textContent = zipCode; const resultElement = document.createElement('div'); resultElement.id = `popularWeatherResult-${zipCode}`; resultElement.classList.add('weather-info'); listItem.appendChild(zipCodeText); listItem.appendChild(resultElement); popularZipCodeList.appendChild(listItem); }); } // Function to fetch weather data for a popular zip code and display it function fetchWeatherForPopularZipCode(zipCode) { const resultElement = document.getElementById(`popularWeatherResult-${zipCode}`); if (resultElement) { fetchWeather(zipCode, resultElement); } } // Function to fetch weather data for a saved zip code and display it function fetchWeatherForSavedZipCode(zipCode) { const resultElement = document.getElementById(`weatherResult-${zipCode}`); if (resultElement) { fetchWeather(zipCode, resultElement); } } // Function to remove a zip code from the list function removeZipCode(zipCode) { let storedZipCodes = JSON.parse(localStorage.getItem('zipCodes')) || []; storedZipCodes = storedZipCodes.filter(storedZipCode => storedZipCode !== zipCode); localStorage.setItem('zipCodes', JSON.stringify(storedZipCodes)); displayStoredZipCodes(storedZipCodes); } });
weather_app/src/test/java/com/service/weather/DataInitializerTest.java
weather_app/src/test/java/com/service/weather/DataInitializerTest.java
package com . service . weather ;
import com . service . weather . model . ZipCode ;
import com . service . weather . repository . ZipCodeRepository ;
import com . service . weather . service . DataInitializer ;
import org . junit . jupiter . api . BeforeEach ;
import org . junit . jupiter . api . Test ;
import org . junit . jupiter . api . extension . ExtendWith ;
import org . mockito . InjectMocks ;
import org . mockito . Mock ;
import org . mockito . junit . jupiter . MockitoExtension ;
import static org . mockito . Mockito . * ;
/**
* The DataInitializerTest class tests the DataInitializer class to ensure that it initializes the database correctly.
* It uses Mockito to mock the ZipCodeRepository and verifies interactions with it.
*/
@ ExtendWith ( MockitoExtension . class )
public class DataInitializerTest {
@ Mock
private ZipCodeRepository zipCodeRepository ;
@ InjectMocks
private DataInitializer dataInitializer ;
@ BeforeEach
public void setUp () {
// Ensure the mock repository is empty before each test
when ( zipCodeRepository . count ()). thenReturn ( 0L );
}
@ Test
public void testInit () {
when ( zipCodeRepository . count ()). thenReturn ( 0L );
dataInitializer . init ();
verify ( zipCodeRepository , times ( 1 )). count ();
verify ( zipCodeRepository , times ( 1 )). save ( argThat ( zipCode ->
zipCode . getCity (). equals ( "New York" ) && zipCode . getZipCode (). equals ( "10001" )
));
verify ( zipCodeRepository , times ( 1 )). save ( argThat ( zipCode ->
zipCode . getCity (). equals ( "San Francisco" ) && zipCode . getZipCode (). equals ( "94114" )
));
verify ( zipCodeRepository , times ( 1 )). save ( argThat ( zipCode ->
zipCode . getCity (). equals ( "Plano" ) && zipCode . getZipCode (). equals ( "75075" )
));
}
@ Test
public void testInitWithExistingData () {
// Simulate existing data in the repository
when ( zipCodeRepository . count ()). thenReturn ( 3L );
dataInitializer . init ();
verify ( zipCodeRepository , never ()). save ( any ( ZipCode . class ));
}
}
weather_app/src/test/java/com/service/weather/WeatherApplicationTests.java
weather_app/src/test/java/com/service/weather/WeatherApplicationTests.java
package com . service . weather ;
import com . service . weather . model . OpenWeatherMapResponse ;
import com . service . weather . model . WeatherRecord ;
import com . service . weather . service . WeatherService ;
import org . junit . jupiter . api . BeforeEach ;
import org . junit . jupiter . api . Test ;
import org . junit . jupiter . api . extension . ExtendWith ;
import org . mockito . InjectMocks ;
import org . mockito . Mock ;
import org . mockito . junit . jupiter . MockitoExtension ;
import org . springframework . beans . factory . annotation . Value ;
import org . springframework . web . client . RestTemplate ;
import java . util . Arrays ;
import static org . junit . jupiter . api . Assertions . assertEquals ;
import static org . junit . jupiter . api . Assertions . assertNotNull ;
import static org . mockito . ArgumentMatchers . any ;
import static org . mockito . ArgumentMatchers . anyString ;
import static org . mockito . Mockito . when ;
@ ExtendWith ( MockitoExtension . class )
class WeatherApplicationTests {
@ Mock
private RestTemplate restTemplate ;
@ InjectMocks
private WeatherService weatherService ;
@ Value ( "${openweathermap.api.key}" )
private String apiKey ;
private final String zipCode = "90210" ;
private OpenWeatherMapResponse mockResponse ;
@ BeforeEach
public void setUp () {
mockResponse = new OpenWeatherMapResponse ();
OpenWeatherMapResponse . Main main = new OpenWeatherMapResponse . Main ();
main . setTemp ( 72.0 );
main . setFeels_like ( 70.0 );
main . setTemp_min ( 68.0 );
main . setTemp_max ( 75.0 );
main . setHumidity ( 50 );
OpenWeatherMapResponse . Wind wind = new OpenWeatherMapResponse . Wind ();
wind . setSpeed ( 5.0 );
OpenWeatherMapResponse . Weather weather = new OpenWeatherMapResponse . Weather ();
weather . setIcon ( "10d" );
weather . setId ( 800 );
mockResponse . setMain ( main );
mockResponse . setWind ( wind );
mockResponse . setWeather ( Arrays . asList ( weather ));
mockResponse . setName ( "New York" );
when ( restTemplate . getForObject ( anyString (), any ())). thenReturn ( mockResponse );
}
@ Test
public void testGetWeatherByZipCode () {
WeatherRecord result = weatherService . getWeatherByZipCode ( zipCode );
assertNotNull ( result );
assertEquals ( zipCode , result . getZipCode ());
assertEquals ( 72.0 , result . getTemperature ());
assertEquals ( 70.0 , result . getFeelsLike ());
assertEquals ( 68.0 , result . getTempMin ());
assertEquals ( 75.0 , result . getTempMax ());
assertEquals ( 50 , result . getHumidity ());
assertEquals ( 5.0 , result . getWindSpeed ());
assertEquals ( "New York" , result . getCity ());
assertEquals ( "https://openweathermap.org/img/wn/[email protected]" , result . getIcon ());
assertEquals ( 800 , result . getConditionCode ());
}
@ Test
public void testGetWeatherByZipCodeWithEmptyResponse () {
when ( restTemplate . getForObject ( anyString (), any ())). thenReturn ( null );
RuntimeException exception = null ;
try {
weatherService . getWeatherByZipCode ( zipCode );
} catch ( RuntimeException e ) {
exception = e ;
}
assertNotNull ( exception );
assertEquals ( "Unable to fetch weather data" , exception . getMessage ());
}
}
weather_app/src/test/java/com/service/weather/ZipCodeServiceTest.java
weather_app/src/test/java/com/service/weather/ZipCodeServiceTest.java
package com . service . weather ;
import com . service . weather . model . ZipCode ;
import com . service . weather . repository . ZipCodeRepository ;
import com . service . weather . service . ZipCodeService ;
import org . junit . jupiter . api . BeforeEach ;
import org . junit . jupiter . api . Test ;
import org . junit . jupiter . api . extension . ExtendWith ;
import org . mockito . InjectMocks ;
import org . mockito . Mock ;
import org . mockito . junit . jupiter . MockitoExtension ;
import java . util . Arrays ;
import java . util . List ;
import static org . junit . jupiter . api . Assertions . * ;
import static org . mockito . Mockito . * ;
@ ExtendWith ( MockitoExtension . class )
public class ZipCodeServiceTest {
@ Mock
private ZipCodeRepository zipCodeRepository ;
@ InjectMocks
private ZipCodeService zipCodeService ;
private ZipCode zipCode1 ;
private ZipCode zipCode2 ;
@ BeforeEach
public void setUp () {
zipCode1 = new ZipCode ( 1L , "City1" , "10001" );
zipCode2 = new ZipCode ( 2L , "City2" , "10002" );
}
@ Test
public void testGetAllZipCodes () {
when ( zipCodeRepository . findAll ()). thenReturn ( Arrays . asList ( zipCode1 , zipCode2 ));
List < ZipCode > zipCodes = zipCodeService . getAllZipCodes ();
assertEquals ( 2 , zipCodes . size ());
verify ( zipCodeRepository , times ( 1 )). findAll ();
}
@ Test
public void testAddZipCode () {
when ( zipCodeRepository . save ( zipCode1 )). thenReturn ( zipCode1 );
ZipCode savedZipCode = zipCodeService . addZipCode ( zipCode1 );
assertNotNull ( savedZipCode );
assertEquals ( "10001" , savedZipCode . getZipCode ());
verify ( zipCodeRepository , times ( 1 )). save ( zipCode1 );
}
@ Test
public void testRemoveZipCode () {
doNothing (). when ( zipCodeRepository ). deleteById ( 1L );
zipCodeService . removeZipCode ( 1L );
verify ( zipCodeRepository , times ( 1 )). deleteById ( 1L );
}
}
weather_app/weather.iml
,
CMSC 495 FINAL REPORT 1
Final Report
Names of Group Members
CMSC 495 – Section XXXX
DATE
CMSC 495 FINAL REPORT 2
Table of Contents
1. Overview …………………………………………………………………………………………………………… 3
2. Project Plan ……………………………………………………………………………………………………….. 4
3. Requirements Specification ………………………………………………………………………………….. 4
4. System Specification ……………………………………………………………………………………………. 4
5. User's Guide ………………………………………………………………………………………………………. 4
6. Test Plan and Results ………………………………………………………………………………………….. 5
7. Design and Alternate designs ………………………………………………………………………………… 5
8. Development History …………………………………………………………………………………………… 8
9. Conclusions ……………………………………………………………………………………………………… 11
9.1. Lessons Learned ……………………………………………………………………………………………………. 11
9.2 Design Strengths ……………………………………………………………………………………………………. 12
9.3 Limitations ……………………………………………………………………………………………………………. 13
9.4. Suggestions for Future Improvement ……………………………………………………………………….. 13
CMSC 495 FINAL REPORT 3
1. Overview
The Plate License and Tag Editor (PLaTE) application was designed to automate the license
plate management division of the DMV. Features provided by the application include:
License plate data management including adding and deleting records
Renewals of existing license plates
Ordering new license plates
Sending payment information to credit card companies securely
Storage of application data including customer data, vehicle data, license plate data
The application operates though a Python based Graphic User Interface (GUI) with a SQL based
database for information storage. The application runs on either Windows or Mac systems that
have python and SQLite loaded on the system.
The application has 3 major components, the GUI, the database, and the backend code.
Development of the system was accomplished by a two-person team (Pearce, Rosario-Baez).
Being that the development team had a limited manpower pool, the entire development team
were involved almost every of the application management and oversight of the major portions
of the development were assigned to specific individuals as follows:
GUI development – Name 1
Database management – Name 2
Python application backend code – Name 3
Documentation – Name
CMSC 495 FINAL REPORT 4
2. Project Plan
The finalized Version 3 of the Project Plan is embedded in this document. Open it by clicking on
the icon below.
3. Requirements Specification
Requirement specifications are covered in the finalized project plan. Access it by clicking on the
icon in the previous section.
4. System Specification
The application will come with the Python GUI, SQL code to place the required tables on any
SQL database, and the Python code to run the GUI/SQL database integration. The Python GUI
will communicate with the SQL database to add, view, and delete customer records. These
records will be used to keep track who owns a vehicle in the state of Maryland and help
Maryland drivers renew and obtain new license plates to maintain proper ownership of the
vehicle.
5. User's Guide
The PLaTE Version 3 User Guide is a comprehensive document that has been vetted by the team
and the professor on through multiple revisions. The current revision is a clearly laid out step-by-
step guide to every function of the PLaTE program. Each process contains figures of each step of
5 CMSC 495 FINAL REPORT
the process to guide an inexperienced user through the program. The finalized Version 3 of
the User Guide is embedded in this document. Open it by clicking on the icon below.
6. Test Plan and Results
The test plan documents, and results have been key to ensuring that the release of our program
was successful. Combing the GUI and associated code step by step with the test pans have
helped us to identify problems that would have made it into production. All problems found have
been fixed until the test plan could be ran with no failures
The Finalized Test Plan and its attachments are embedded in this document. Open them by
clicking on their icons below.
7. Design and Alternate designs
Primary designs for the program were comprehensive, the original program UML is shown
below:
CMSC 495 FINAL REPORT 6
UML
Figure 1. UML Part 1
Figure 2. UML Part 2
CMSC 495 FINAL REPORT 7
Although this fix helped the user to be able to easily see records, we quickly realized that we did
not take into consideration that a customer could own more than one car and could there for have
multiple cars and plates that would have to be connected and able to be accessed individually for
display and renewal. purposes. The solution to that was several functions and a new window.
The new functionality of the program made the program look to see if a customer had more than
one vehicle when their driver’s license was entered in the normal process. If there was only one
record everything processed as normal. If there was more than one the window below would
open showing the VIN, make, model, and year for all the vehicles associated with the driver’s
license entered.
Figure 3. UML Part 3
CMSC 495 FINAL REPORT 8
Figure 4. Multiple Record User Interface
The user could then choose which record they wished to use by clicking on the record in the
displayed list and pressing submit. The record that was selected would then process. This
window and the functionality attached it fixed a major shortfall in the program. The program
remains in its final state with only the addition of this one window and popups to tell users the
success or failures of their entries.
The Finalized Design Plan is embedded in this document. Open it by clicking on their icons
below.
8. Development History
The Plate program s developmental history is best displayed through our milestone chart and
later quite comprehensively through our phase submissions. On the milestone chart shown
below, the black lines show the milestones as they were set at the beginning of the project. The
CMSC 495 FINAL REPORT 9
green lines show the actual times. Most time frames were very close to the prospective times set
forth at the beginning. Times for GUI assembly, backend coding, and connection of components
are shown longer as the GUI and its functionality was an ongoing process after the initial build
for the entire project. All of these times ran over their estimates but concluded in plenty of time
while leaving a much better program than in the beginning.
Figure 5. Milestones of the Project VS Actual Times
10 CMSC 495 FINAL REPORT
An overview of the three phases of this developmental processes where as follows:
PHASE I (5 Sept 15 – Sept 21)
Name Got to work on learning PYSimpleGUI and getting the initial build of the GUI together.
This was a major undertaking as neither member of the team had ever used Python to write a
GUI.
Name started writing pseudo functions for the backend and creating SQL tables that would hold
the data needed for the program and hold enough information on each customer, vehicle, and
license plate so that they could be attached to their corresponding records and be used by the
GUI and backend code.
PHASE II (Sept 22 – Sept 28)
Namecontinue to work on the GUI, adding functionality while coordinating with Pearce to
ensure that the backend code was written to correspond with the database as it was coming
together.
Name added 20 rows of values to each table to use when constructing the backend code. Pearce
then wrote code into each function, testing that each function worked with the SQL database
adding, deleting, and viewing the information from the database.
PHASE III (Sept 29 – Oct 5)
The program is functionally complete at this point and bugs are being discovered as we wade
through testing. At this point in the project both member of the team had to be very careful of
version control. Coding was often done on Zoom with both member working through any
problems that had arisen.
CMSC 495 FINAL REPORT 11
9. Conclusions
Over the past eight weeks, team one has put their shoulder to the wheel and fought through some
difficult learning curves. Despite all that, we feel that the product we produced is hearty and does
what we want it to. We did not, at any time during the process, say to ourselves, “let’s skip this
functionality so that we can get this thing done”. We fought through some areas, but all aspects
of the program’s functionality were as we envisioned them and some even turned out better than
we had expected. Both team members are much better programmers and project coordinators
because of the programming tasks and teamwork involved in this project.
9.1. Lessons Learned
There are several lessons learned during this project:
First, be flexible. There will almost always be design changes that must happen once you start
coding. They may be small, but they may affect other parts of the program. Accept that this is
going to happen and don’t try to stall or hide them. Triage them as they are found and decide
what needs to be done to make things right. We ran into a few such items in our code as we went
along. Either a program logic item that we had not considered or one that we had considered but
when applied acted differently. We discussed fixes when the problems were identified and got
after it. We are proud to say that there is not one problem, that we identified that, that we did not
fix.
Next, keep to your timelines if possible. We set milestones and either kept or exceeded
them. This allowed us time to meet incoming problems head on. Not only in our code but in our
home life and jobs. Because we stayed a focused and did not let ourselves get behind on the
CMSC 495 FINAL REPORT 12
coding or the documentation, we were able to overcome not only unseen code problems but also
events that were out of the team’s control that took a team member offline for a day or two.
Lastly, the answers are out there. We are fortunate today to have a vast repository of
knowledge at our fingertips. If you wish to learn or clarify something. The answer is most often
just a internet search away. We were lacking some of the knowledge we needed to complete this
project at the beginning. We identified that fact early and taught ourselves what we needed with
many hours of research. The lesson learned is that you can do almost anything with coding
today, it may take some research, but it is possible.
9.2 Design Strengths
Our program is solidly built and held together with strong code. Lines of code that were used
more than once were made into functions so that they could be managed easier, and the code
would be easier to read from an outside perspective. We did not allow for covering or burying
flaws that we found while testing. If a rewrite of a section of the code was required to fix issues
raised by testing, it was rewritten. This would often set us back, but we had made provisions in
the planning for this and stayed with or ahead of our timeline as a rule.
We designed the program to be easy to use. Sections of the GUI that require use input are
highlighted when that input is needed. All other input areas are shaded out. Popup boxes notify
users when they are using the program incorrectly or when errors are made during data input.
Visual examples are given of plates as they are ordered aid the user and customer to verify what
they are ordering.
CMSC 495 FINAL REPORT 13
The GUI is easily modifiable. Future upgrades to the program could easily modify, replace, or
add windows in response to user feedback. This will allow the software development cycle to
continue easily as it comes around in its cyclical manner.
9.3 Limitations
As far as limitations go for the program, our team focused on removing limitations when they
were discovered in the design process or when coding started. That is not to say that our program
does not have limitations. It means that we have far fewer limitation than we would have if we
would not have worked under that credo. There are limitations both remaining both
programmatically and structurally.
The SQLite database will only hold approximately 281 terabytes of data. (SQLite.org,
2021)
Each table in the database can only hold 18,446,744,073,709,551,616 rows of data
(SQLite.org, 2021)
We currently do not automatically track expiration dates in the database. This must be
done manually and could be made automated in future releases of the program
Current versions of Python and SQLite must be loaded on each machine that wishes to
use the program.
9.4. Suggestions for Future Improvement
Our team has kept an eye out for future improvements as the program was coming together.
Some of those improvements that were identified we were able to incorporate immediately.
Others were noted for the future. One of the upgrades we were able to incorporate was the ability
CMSC 495 FINAL REPORT 14
to select which record was being selected when the customer hand more than one vehicle. How
the user performed this task was upgraded from a manual count of the records by the user to a
list populated with the options available that the user can click on their selection and submit it.
There was a lot of blood sweat and tears to bring that upgrade into production, but we
accomplished it and it works beautifully.
Some of the future improvements that we identified for future versions of the program was the
addition of more plate backgrounds beyond the eight versions we currently offer, an expiration
date tracker that automatically combs the database and provides that information to the user. This
task currently must be done manually. Lastly, combing the program into an executable file would
make the initial download and startup of the program easier and could be accomplished by an
average user instead of a programmer.
CMSC 495 FINAL REPORT 15
REFERENCES
Geeks for Geeks.org. (2019, March 27). Python | Convert list of tuples to list of list.
GeeksforGeeks. https://www.geeksforgeeks.org/python-convert-list-of-tuples-to-list-of-list/
Programiz. (n.d.). Python list remove(). Programiz: Learn to Code for
Free. https://www.programiz.com/python-programming/methods/list/remove
PySimpleGUI. (2021). PySimpleGUI. https://pysimplegui.readthedocs.io/en/latest/
Python, R. (2020, June 17). PySimpleGUI: The simple way to create a GUI with Python – Real Python.
Python Tutorials – Real Python. https://realpython.com/pysimplegui-python/
Python Software Foundation. (2021). Sqlite3 — DB-API 2.0 interface for SQLite databases — Python
3.9.7 documentation. 3.9.7 Documentation. https://docs.python.org/3/library/sqlite3.html
SQLite.org. (2021, June 18). Implementation limits for SQLite. SQLite. https://www.sqlite.org/limits.html
Trinket.io. (2021). The basics of the pysimplegui program. https://pysimplegui.trinket.io/demo-
programs#/demo-programs/the-basic-pysimplegui-program
Tutorialspoint. (2021). SQLite – Python. Biggest Online Tutorials
Library. https://www.tutorialspoint.com/sqlite/sqlite_python.htm
Tutorialspoint. (2021). SDLC – Overview. The Biggest Online Tutorials Library – AppML, AI with Python,
Behave, Java16, Spacy. https://www.tutorialspoint.com/sdlc/sdlc_overview.htm
W3 Schools. (2021). SQL SELECT statement. W3Schools Online Web
Tutorials. https://www.w3schools.com/sql/sql_select.asp
,
Title: Project Test Plan
Team Members:
Date: July 16, 2024
Introduction
The software project involves developing a weather website that allows users to input a zip code and receive real-time weather information. This website fetches weather data from an external API and displays various weather parameters, including temperature, humidity, wind speed, and weather conditions such as thunderstorms and heavy rain. The scope of testing for this project encompasses all functionalities of the website to ensure that it performs correctly under various conditions and provides a seamless user experience. This includes ensuring the accuracy of data, compatibility across different browsers, and reliability of the entire system to ensure it meets user requirements and expectations.
Testing Objectives
The primary objectives of the testing effort are to ensure that the weather website operates correctly and efficiently, providing a high-quality user experience. The specific quality attributes to be assessed include functionality, usability, and reliability. The testing will focus on:
· Functionality: Ensuring the core features such as zip code input, weather data retrieval, and display operate correctly. This includes verifying that users can add and remove zip codes, preventing duplicate entries, and handling both valid and invalid zip codes appropriately.
· Usability: Confirming that the user interface is intuitive and easy to navigate, providing a seamless user experience across different devices and screen sizes.
· Reliability: Ensuring the application is dependable, with saved zip codes persisting across sessions and accurate weather information being consistently provided.
By assessing these attributes, the testing effort aims to ensure that the weather website delivers accurate, timely, and reliable weather information while providing a user-friendly experience to its users.
Test Strategy
The overall approach to testing will involve a combination of manual and automated testing methodologies to ensure comprehensive coverage and efficiency. The testing types to be performed include unit testing, integration testing, system testing, and usability testing. Each type of testing plays a critical role in validating different aspects of the weather website, ensuring it meets the highest standards of quality and user satisfaction.
Unit Testing
Unit testing will focus on verifying the functionality of individual components within the system. Each module, such as the zip code input handler, weather data fetcher, and user interface components, will be tested in isolation. This helps identify and fix issues at an early stage, ensuring that each part of the application works as intended.
Automated unit tests will be written to cover various scenarios, including edge cases, to ensure robustness:
1. API Key and Weather Fetching:
· The unit test will mock the behavior of external API calls to ensure that the getWeatherByZipCode method correctly constructs the API URL, handles responses, and populates the WeatherRecord object.
· Tests will cover scenarios such as valid zip code responses, invalid zip codes returning errors, and no response from the API.
2. Error Handling and Edge Cases:
· Tests will verify that the system gracefully handles errors, such as invalid zip codes or network issues, by displaying appropriate messages and maintaining application stability.
· Edge cases, such as empty inputs or malformed zip codes, will be thoroughly tested to ensure robust input validation and error handling.
Integration Testing
Integration testing will verify that different components of the weather website work together seamlessly. This involves testing the interactions between the frontend and backend, as well as between various backend services. The goal is to ensure that data flows correctly through the system and that integrated components interact as expected. Integration tests will include scenarios such as fetching weather data for a given zip code and updating the user interface with the retrieved information.
System Testing
System testing will assess the end-to-end functionality of the entire weather website. This comprehensive testing approach will cover all user interactions and system workflows, from entering a zip code to displaying weather information and managing saved zip codes. System testing will ensure that the application meets its functional requirements and provides a reliable user experience.
Test Scope
The test scope includes all functional and non-functional aspects of the weather website. Functional testing will cover core features such as zip code input handling, weather data retrieval from the API, and the display of weather information on the user interface. Non-functional testing will assess usability, reliability, and cross-browser compatibility. The boundaries of the testing effort exclude testing on deprecated browsers, and network conditions outside typical user scenarios. Additionally, backend integrations with external weather data providers will be tested under the assumption that their APIs are functional and reliable.
Test Cases
The test will focus on the following test cases to ensure comprehensive coverage of the system's functionality:
1. Valid Zip Code Fetch: Verify that entering a valid zip code fetches and displays the correct weather information.
2. Invalid Zip Code Error: Ensure that entering an invalid zip code results in an appropriate error message without crashing the application.
3. Adding Valid Zip Code to List: Confirm that valid zip codes can be added to a list for quick access.
4. Invalid Zip Code Addition Prevention: Verify that attempting to add an invalid zip code does not add it to the list.
5. Prevent Duplicate Zip Codes in List: Ensure that duplicate zip codes cannot be added to the list.
6. Remove Zip Code from List: Check that users can remove zip codes from their saved list.
7. Fetch Weather for Saved Zip Codes on Load: Ensure that the weather information for saved zip codes is fetched and displayed when the application is loaded.
8. Severe Weather Alert: Verify that the application can handle and display alerts for severe weather conditions when a relevant zip code is entered.
9. Persistent Zip Codes on Reopen: Ensure that saved zip codes are retained and reloaded when the application is reopened.
10. Cross-Browser Compatibility: Confirm that the website functions correctly across different browsers such as Chrome, Firefox, Safari, and Edge.
Testing Procedures
Testing procedures will involve specific steps for executing each test case, including setting up the test environment, preparing test data, and recording results. Test data preparation will involve creating a set of valid and invalid zip codes, as well as simulating various user interactions. The test environment configuration will ensure that the backend server, frontend client, and network conditions are consistent with typical user scenarios.
Testing Schedule
The testing schedule for the weather website outlines the timelines for each phase of the testing effort, ensuring that all testing activities are completed within the project timeline. The schedule includes deadlines for unit testing, integration testing, system testing, and usability testing, with specific milestones and deliverables. Each phase has been allocated sufficient time for test case development, test execution, defect resolution, and re-testing. The testing schedule is as follows:
July 10 – July 11: Unit Testing
· July 10:
· Develop unit test cases for the zip code input handler and weather data fetcher.
· Set up the testing environment and write automated unit tests using JUnit and Mockito.
· July 11:
· Execute unit tests.
· Identify and log any defects found during unit testing.
· Begin fixing identified defects.
July 12 – July 14: Integration Testing
· July 12:
· Develop integration test cases to verify interactions between the frontend and backend components.
· Set up the testing environment for integration tests.
· July 13:
· Execute integration tests.
· Identify and log any defects found during integration testing.
· July 15:
· Fix identified defects and re-test to verify the fixes.
July 17 – July 20: System Testing
· July 17:
· Develop system test cases to cover end-to-end functionality of the weather website.
· Prepare the testing environment for system testing.
· July 19:
· Execute system tests.
· Identify and log any defects found during system testing.
· July 20:
· Fix identified defects and re-test to verify the fixes.
Testing Resources
To run the application and perform comprehensive testing, the following resources will be required:
Personnel
· Dedicated Testers:
· William Nguewa
· Taehoon Song
· Developers: Available to fix defects and provide support during the testing process.
· Tsegent Tekilemariam
Equipment
· Test Devices: Each tester will need a personal computer or laptop capable of running Java 17, an IDE, and multiple browsers for testing purposes.
Software Tools
· Java 17: Ensure that all testers have Java 17 installed, as it is required to run the Spring Boot application.
· Integrated Development Environment (IDE): An IDE such as IntelliJ IDEA or Eclipse for developing, debugging, and running the application.
· Multiple Browsers: Ensure that the application is tested on the latest versions of major browsers, including:
· Google Chrome
· Mozilla Firefox
· Microsoft Edge
Budget
No additional budget is required as all necessary tools and software are open-source and free to use, and existing personal computers or laptops will be utilized for testing purposes.
Execution
· Running the Application: Testers will run the Spring Boot application on their local devices.
· Browser Testing: Testers will open the site on multiple browsers and perform the testing as per the test cases.
By ensuring these resources are in place, the testing team will be well-equipped to conduct thorough and effective testing of the weather website, ensuring it meets all functional and non-functional requirements.
Defect Management
Establishing a robust defect management process is crucial for identifying, reporting, and tracking defects or bugs encountered during testing.
Identifying Defects
· Testing Execution: During the execution of test cases, testers will document any discrepancies between the expected and actual results.
Reporting Defects
· Defect Tracking Tool: Jira
· Defect Report: Each defect will be reported with detailed information to facilitate quick resolution. A standard defect report will include:
· Defect ID: A unique identifier for the defect.
· Summary: A brief description of the defect.
· Description: Detailed information about the defect, including steps to reproduce, expected results, and actual results.
· Priority: The urgency of addressing the defect (e.g., high, medium, low).
· Attachments: Screenshots, logs, or any other relevant files that provide additional context.
Tracking Defects
· Defect Lifecycle: Establish a lifecycle for tracking defects from discovery to resolution. Typical stages include:
· New: The defect has been identified and logged.
· Assigned: The defect has been assigned to a developer for resolution.
· In Progress: The developer is actively working on fixing the defect.
· Fixed: The defect has been resolved and awaits verification.
· Verified: The fix has been verified by a tester.
· Closed: The defect is considered resolved and closed.
· Reopened: If the defect reoccurs, it can be reopened for further investigation.
By following this defect management process, the testing team can efficiently identify, report, and track defects, ensuring timely resolution and contributing to the overall quality and reliability of the weather website.
Summary
This test plan for the weather website outlines a structured approach to ensure the application delivers accurate, reliable, and user-friendly weather information. The testing strategy includes unit testing, integration testing, and system testing, each targeting specific components and interactions within the application. The detailed testing schedule and resource allocation, including Java 17, multiple browsers, and an IDE, provide a clear roadmap for executing comprehensive tests. This approach ensures that each aspect of the website is thoroughly examined and meets the desired quality standards.
A robust defect management process is also established to identify, report, and track issues efficiently. By leveraging the JIRA tool, the testing team can systematically document and resolve defects, ensuring a smooth and reliable user experience. This well-defined testing plan and defect management process contribute to the overall goal of delivering a high-quality weather website that meets user expectations and performs reliably in real-world scenarios.
,
CMSC 495 Phase I Source Code Phase I Source Code
Cover Page
Project Title: Weather Application Project
Team Members:
–
Introduction
This project is a weather application designed to fetch and display weather information based on a user's zip code. It incorporates various modern technologies and methodologies, including Spring Boot for the backend, HTML, CSS, and JavaScript for the frontend, and integration with the OpenWeatherMap API.
Objective
· Develop a weather application to fetch and display real-time weather data for user-specified locations.
· Provide a detailed weather forecast for the upcoming week.
· Enable users to set alerts for specific weather conditions such as rain, snow, and high temperatures.
Review the Phase I Project Scope
Deliverables:
· A functional weather application with a user-friendly GUI.
· Ability for users to search for weather updates by location.
· Detailed weather forecasts and weather alerts.
Boundaries:
· The application will only support locations that are accessible via the chosen weather API.
· The application will be developed for Java-compatible operating systems only.
Limitations:
· Real-time data accuracy is dependent on the reliability of the weather API service.
· The application will not include advanced features such as radar or satellite imagery.
3. Project Requirements
Functional Requirements:
· Select location and display weather information.
· Set and manage weather alerts.
· Display current weather conditions and forecasts.
Non-functional Requirements:
· The application must have a responsive and intuitive GUI.
· The application should perform data fetching and display updates promptly.
Technical Requirements:
· Operating System: Windows or any Java-compatible OS.
· Application Software: Java JRE.
· Tools: Java Development Kit (JDK), Integrated Development Environment (IDE) such as IntelliJ IDEA or Eclipse, access to a weather API (e.g., OpenWeatherMap).
2. Design the Software Architecture
Architecture Overview
Frontend
· Technologies: HTML, CSS, JavaScript
· Description: This layer is responsible for the user interface and user experience. It consists of HTML for structure, CSS for styling, and JavaScript for interactivity. The frontend communicates with the backend through RESTful APIs.
· Components:
· HTML files for the structure of the web pages
· CSS files for styling and layout
· JavaScript files for handling user interactions and making API requests
· Static images for weather icons based on temperature conditions
Backend
· Technologies: Spring Boot, Java 17, RestTemplate
· Description: This layer handles the business logic of the application. It processes requests from the frontend, interacts with external APIs, and returns the appropriate responses.
· Components:
· WeatherService: A service class that fetches weather data from the OpenWeatherMap API using RestTemplate.
· WeatherController: A REST controller that handles HTTP requests from the frontend and uses WeatherService to get the required data.
Data Layer
· Technologies: H2 Database (in-memory database for simplicity during development)
· Description: This layer is responsible for data storage and retrieval. It stores user preferences, such as saved zip codes, and caches weather data if necessary.
· Components:
· Entities representing the data model, such as WeatherRecord.
· Repositories for CRUD operations on the data.
,
Title: Weather App Project Design
Team Members:
Date: July 2, 2024
Table of Contents
1. Introduction
2. Project Scope
3. Project Requirements
4. Project Methodology
5. Work Breakdown Structure
6. Project Schedule
7. Project Risks
8. Project Evaluation Plan
9. References
1. Introduction
This design document outlines the comprehensive plan for the development of a weather application by Group 4. It includes an analysis of the project’s requirements, a work breakdown of the proposed project, a detailed project schedule, risk management plans, and an evaluation plan.
2. Project Scope
Objectives:
· Develop a weather application to fetch and display real-time weather data for user-specified locations.
· Provide a detailed weather forecast for the upcoming week.
· Enable users to set alerts for specific weather conditions such as rain, snow, and high temperatures.
Deliverables:
· A functional weather application with a user-friendly GUI.
· Ability for users to search for weather updates by location.
· Detailed weather forecasts and weather alerts.
Boundaries:
· The application will only support locations that are accessible via the chosen weather API.
· The application will be developed for Java-compatible operating systems only.
Limitations:
· Real-time data accuracy is dependent on the reliability of the weather API service.
· The application will not include advanced features such as radar or satellite imagery.
3. Project Requirements
Functional Requirements:
· Select location and display weather information.
· Set and manage weather alerts.
· Display current weather conditions and forecasts.
Non-functional Requirements:
· The application must have a responsive and intuitive GUI.
· The application should perform data fetching and display updates promptly.
Technical Requirements:
· Operating System: Windows or any Java-compatible OS.
· Application Software: Java JRE.
· Tools: Java Development Kit (JDK), Integrated Development Environment (IDE) such as IntelliJ IDEA or Eclipse, access to a weather API (e.g., OpenWeatherMap).
4. Project Methodology
Chosen Approach: Agile
Justification: Agile methodology allows for iterative development and frequent reassessment of the project’s direction, which is essential for accommodating the dynamic nature of weather data and user requirements. Regular feedback cycles will enable continuous improvement and ensure that the final product meets user expectations.
5. Work Breakdown Structure (WBS)
1. Project Initiation:
· Meet Team
· Discuss Roles
· Communication Plan
· Discuss Project Options
2. Project Planning:
· Project Plan
· Select Sections
· Execute Sections
· Combine and Submit
3. Design Phase:
· Design
· Config File Load
· Main UI
· User’s UI
4. Functional Requirements
1. API Integration: Integrate with OpenWeatherMap API to fetch real-time weather data.
2. Data Processing: Process and format the weather data to be usable by the frontend.
3. User Authentication: Implement user authentication to manage user-specific settings and preferences.
4. Database Management: Store user data, preferences, and possibly historical weather data for analysis.
Non-Functional Requirements
1. Scalability: Ensure the backend can handle a growing number of users and requests.
2. Security: Secure data transmission and user information with proper authentication and authorization mechanisms.
3. Performance: Optimize the backend to handle API requests and responses with minimal latency.
4. Maintainability: Write clean, modular, and well-documented code for ease of maintenance.
Technology Stack
1. Programming Language: Java
2. Framework: Spring Boot
3. Database: SQL
4. API Client: RestTemplate (Spring Boot)
5. Authentication: Spring Security with JWT
4. Phase 1 Build
1. Config File Load
· Frontend: Set up configuration files for UI themes, localization, and initial settings.
· Backend:
· Load configuration files for database connections, API keys, and other environment-specific settings.
· Implement Spring Boot configuration properties to manage different environments.
2. Main UI
· Frontend:
· Design and implement the main user interface using JavaFX.
· Ensure the main UI includes essential components such as the weather display, search bar, and navigation menu.
· Backend:
· Develop core API endpoints in Spring Boot to fetch weather data.
· Implement the logic to call OpenWeatherMap API and process the responses.
· Set up initial database schema using PostgreSQL to store user preferences and weather data.
Phase 2 Build
1. User’s UI
· Frontend:
· Create user-specific interfaces, including login, registration, and profile management screens.
· Implement functionality for users to save their settings and preferences.
· Backend:
· Implement user authentication and authorization using Spring Security and JWT.
· Develop endpoints for user management, including registration, login, and profile updates.
· Create database tables for user information and implement CRUD operations.
Phase 3 Build
1. Final Compilation of All Units
· Frontend:
· Integrate all UI components and ensure seamless navigation between different screens.
· Conduct thorough testing of the entire frontend to ensure functionality and responsiveness.
· Backend:
· Finalize and optimize all API endpoints.
· Ensure all data processing and storage mechanisms are functioning correctly.
· Perform load testing and optimize the backend for performance.
· Deploy the backend to a cloud service (e.g., AWS, Heroku) and ensure it is accessible by the frontend.
Combined Tasks
1. API Endpoint Development
· Develop RESTful endpoints in Spring Boot to serve data to the frontend.
· Ensure endpoints are secure and follow REST best practices.
2. Frontend-Backend Integration
· Implement API calls in the frontend to retrieve data from the backend.
· Ensure seamless data flow between the frontend and backend.
3. Testing
· Conduct end-to-end testing to ensure that the frontend and backend work together as expected.
· Identify and fix any integration issues.
5. Testing Phase:
· Use Guide/Test Plan
· Individual Test Plans
· First Draft (Test Plans)
· Individual User Guides
· First Draft (User Guide)
· Final Draft (Test Plan)
· Final Draft (User Guide)
6. Project Schedule
Development Schedule with Milestones (June – August 2024):
Week |
Activity |
1 (08/04/2024) |
Meet Team |
2 (08/04/2024) |
Discuss roles, Communication plan |
3 (08/04/2024) |
Project Plan, Select sections |
4 (08/04/2024) |
Execute sections, Combine and submit |
5 (08/04/2024) |
Use Guide/Test Plan, Individual Test Plans |
6 (08/10/2024) |
First Draft (Test Plans), Individual User Guides |
7 (08/10/2024) |
Final Draft (Test Plan), Final Draft (User Guide) |
8 (08/10/2024) |
Design, Config File Load, Main UI |
9 (08/12/2024) |
Phase 1 Build |
10 (08/21/2024) |
Phase 2 Build |
11 (08/30/2024) |
Phase 3 Build, Testing |
7. Project Risks
Potential Risks:
· API Reliability: Dependency on the weather API service for real-time data.
· Development Delays: Potential delays in meeting development milestones.
· Technical Challenges: Integration issues between different modules of the application.
Mitigation Strategies:
· API Reliability: Research and select a robust and reliable weather API with high uptime.
· Development Delays: Implement a buffer in the schedule for unforeseen delays and regularly track progress.
· Technical Challenges: Regular team meetings to address and resolve technical issues promptly.
8. Project Evaluation Plan
Evaluation Criteria:
· Functionality: Ensure all features (location search, weather display, alert settings) work as intended.
· Performance: The application should fetch and display data promptly without lag.
· User Interface: The GUI should be user-friendly and intuitive.
· Reliability: The application should handle errors gracefully and provide meaningful feedback to the user.
· Documentation: Comprehensive user guides and test plans should be available.
Evaluation Methods:
· Testing: Conduct unit testing, integration testing, and user acceptance testing.
· User Feedback: Collect feedback from a sample of target users and incorporate improvements.
· Review: Regular project reviews to assess progress against milestones and make necessary adjustments.
9. References
· OpenWeatherMap. (n.d.). OpenWeatherMap API documentation. Retrieved from https://openweathermap.org/api