Witam,
Chciałem prosić o poradę przy pisaniu testów jednostkowych. Niedawno stworzyłem mały projekt do wyświetlania prognozy pogody przy użyciu JavyFX - kod można znaleźć TUTAJ
Teraz chciałbym napisać do tej aplikacji testy jednostkowe natomiast mam problem z określeniem zakresu, jaki te testy powinny obejmować. Jestem świadom, że testy powinny obejmować tylko kod, stworzony przeze mnie, oraz że nie ma sensu pisać testów dla prostych getterów i setterów. Natomiast mam dylemat co do pozostałej części.
Pierwszy przykład:
public class Geolocation {
private final InputStream databasePath = getClass().getResourceAsStream(Config.GEOLOCATION_DATABASE_PATH);
public String getCityName() throws IOException, GeoIp2Exception {
String ipAddress = getIpAddress();
File database = streamToFile(databasePath);
DatabaseReader databaseReader = new DatabaseReader.Builder(database).build();
InetAddress inetAddress = InetAddress.getByName(ipAddress);
CityResponse cityResponse = databaseReader.city(inetAddress);
return cityResponse.getCity().getName();
}
private String getIpAddress() throws IOException {
URL url = new URL(Config.CHECK_IP_URL_PATH);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(url.openStream()));
return bufferedReader.readLine();
}
private static File streamToFile(InputStream in) throws IOException {
File tempFile = File.createTempFile(Config.GEOLOCATION_DATABASE_TEMP_FILE_PREFIX, Config.GEOLOCATION_DATABASE_TEMP_FILE_SUFFIX);
tempFile.deleteOnExit();
FileOutputStream out = new FileOutputStream(tempFile);
in.transferTo(out);
return tempFile;
}
}
To jest klasa, której metody mają za zadanie zwrócić aktualną lokalizację użytkownika. Wszystkie metody są stworzone przeze mnie więc teoretycznie powinienem je przetestować, ale na przykład metoda getIpAddress będzie zwracała inną wartość dla różnych użytkowników a przepisywanie tej metody do testu wydaje się bez sensu. Czy w takim razie powinienem pominąć test tej metody? Druga sprawa to metoda getCityName, której zwracana wartość jest zależna właśnie od adresu IP. Tutaj teoretycznie mogę rozszerzyć tę klasę i nadpisać tą metodę dla testu tak aby do zmiennej ipAddress przypisać przypisać stałą wartość. I tutaj mogę sprawdzić czy poprawnie wyciągam nazwę z bazy danych, ale wydaje mi się to zbyt prymitywne podejście. Może ktoś mógłby polecić lepszy pomysł.
Drugi przykład:
public class CurrentWeatherController extends BaseController implements Initializable {
private final CurrentWeatherData currentWeatherData;
@FXML
private Label cityNameLabel;
@FXML
private ImageView currentWeatherImage;
@FXML
private Label currentWeatherTemperature;
@FXML
private Label currentWeatherDescription;
@FXML
private Label currentWindLabel;
@FXML
private ImageView currentWindImage;
@FXML
private Label currentWeatherPressure;
@FXML
private Label currentWeatherHumidity;
public CurrentWeatherController(ViewFactory viewFactory, String fxmlName, CurrentWeatherData currentWeatherData) {
super(viewFactory, fxmlName);
this.currentWeatherData = currentWeatherData;
}
@Override
public void initialize(URL url, ResourceBundle resourceBundle) {
setCityNameLabel();
setCurrentWeatherImage();
setCurrentWeatherTemperatureLabel();
setCurrentWeatherDescriptionLabel();
setCurrentWindLabel();
setCurrentWindImage();
setCurrentWeatherPressureLabel();
setCurrentWeatherHumidityLabel();
}
private void setCityNameLabel() {
String cityName = currentWeatherData.getName().toUpperCase();
cityNameLabel.setText(cityName);
}
private void setCurrentWeatherImage() {
Image image = ImageResolver.getWeatherIcon(currentWeatherData.getWeather().get(0).getIcon());
currentWeatherImage.setImage(image);
}
private void setCurrentWeatherTemperatureLabel() {
String temperature = currentWeatherData.getMain().getTemp() + LabelsDescription.TEMPERATURE_UNIT;
currentWeatherTemperature.setText(temperature);
}
private void setCurrentWeatherDescriptionLabel() {
String description = StringMethods.capitalizeFirstLetter(currentWeatherData.getWeather().get(0).getDescription());
currentWeatherDescription.setText(description);
}
private void setCurrentWindLabel() {
String windLabel = LabelsDescription.WIND_LABEL + currentWeatherData.getWind().getSpeed() + LabelsDescription.WIND_UNIT;
currentWindLabel.setText(windLabel);
}
private void setCurrentWindImage() {
URL url = getClass().getResource(ImageResolver.ARROW_IMAGE_PATH);
Image image = new Image(String.valueOf(url));
int windDeg = currentWeatherData.getWind().getDeg();
currentWindImage.setImage(image);
currentWindImage.setRotate(windDeg);
}
private void setCurrentWeatherPressureLabel() {
String pressureLabel = LabelsDescription.PRESSURE_LABEL + currentWeatherData.getMain().getPressure() + LabelsDescription.PRESSURE_UNIT;
currentWeatherPressure.setText(pressureLabel);
}
private void setCurrentWeatherHumidityLabel() {
String humidityLabel = LabelsDescription.HUMIDITY_LABEL + currentWeatherData.getMain().getHumidity() + LabelsDescription.HUMIDITY_UNIT;
currentWeatherHumidity.setText(humidityLabel);
}
}
To klasa (kontroler), która odpowiada za ustawianie wartości na widoku aplikacji. Większość metod to zwykłe settery dla kontrolek, które dodatkowo wyciągają odpowiednią informację do wyświetlenia. I tutaj mam dylemat czy jest sens pisania testów dla takich metod jeśli mam inny test, który sprawdza czy do obiektu currentWeatherData zostają przypisane właściwe dane z przykładowego pliku json.