diff --git a/logs/hippodrome.log b/logs/hippodrome.log new file mode 100644 index 00000000..59825894 --- /dev/null +++ b/logs/hippodrome.log @@ -0,0 +1,92 @@ +2023-01-23 20:26:39,509 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:26:39,666 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:26:39,700 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:27:48,062 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:27:48,162 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:27:48,185 DEBUG Horse Создание Horse, имя name, скорость 1.0 +2023-01-23 20:29:33,579 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:40:19,243 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:42:34,775 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:43:20,722 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:46:15,850 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:47:33,457 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:50:05,310 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:52:06,591 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:55:32,274 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:56:30,748 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 20:57:14,309 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:09:05,605 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:09:45,544 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:11:07,629 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:16:01,626 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:17:22,602 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:18:00,968 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:19:02,925 DEBUG Hippodrome Создание Hippodrome, лошадей 5 +2023-01-23 21:32:54,628 DEBUG Hippodrome Создание Hippodrome, лошадей 5 +2023-01-23 21:34:55,961 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:35:19,952 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:36:33,614 DEBUG Hippodrome Создание Hippodrome, лошадей 50 +2023-01-23 21:36:33,882 ERROR Hippodrome Horses list is null +2023-01-23 21:36:33,896 DEBUG Horse Создание Horse, имя Horse, скорость 0.6335314534697963 +2023-01-23 21:36:33,896 DEBUG Horse Создание Horse, имя Horse, скорость 0.43009176892586454 +2023-01-23 21:36:33,896 DEBUG Horse Создание Horse, имя Horse, скорость 0.507182091009049 +2023-01-23 21:36:33,896 DEBUG Horse Создание Horse, имя Horse, скорость 0.9158620498480842 +2023-01-23 21:36:33,897 DEBUG Horse Создание Horse, имя Horse, скорость 0.18568932867359256 +2023-01-23 21:36:33,897 DEBUG Horse Создание Horse, имя Horse, скорость 0.31965021793605297 +2023-01-23 21:36:33,897 DEBUG Horse Создание Horse, имя Horse, скорость 0.52078124036609 +2023-01-23 21:36:33,897 DEBUG Horse Создание Horse, имя Horse, скорость 0.9981569725941888 +2023-01-23 21:36:33,897 DEBUG Horse Создание Horse, имя Horse, скорость 0.9198946243355042 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.6006654666722108 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.8631358256598722 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.9946370795427241 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.14566065528860106 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.4645926180164245 +2023-01-23 21:36:33,898 DEBUG Horse Создание Horse, имя Horse, скорость 0.8281699580072763 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.06980829103182662 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.004193813526336743 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.9379561101586087 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.40006395297439123 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.4446705315787328 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.5119509013102479 +2023-01-23 21:36:33,899 DEBUG Horse Создание Horse, имя Horse, скорость 0.6831245388519113 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.4540684075608016 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.36305019132695915 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.9431244490655691 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.29523972353405015 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.8763249864233851 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.915415409127704 +2023-01-23 21:36:33,900 DEBUG Horse Создание Horse, имя Horse, скорость 0.7737126148077987 +2023-01-23 21:36:33,901 DEBUG Horse Создание Horse, имя Horse, скорость 0.8804573488711275 +2023-01-23 21:36:33,901 DEBUG Hippodrome Создание Hippodrome, лошадей 30 +2023-01-23 21:36:33,912 ERROR Hippodrome Horses list is empty +2023-01-23 21:36:33,924 DEBUG Horse Создание Horse, имя Horse, скорость 0.9503494505122779 +2023-01-23 21:36:33,925 DEBUG Horse Создание Horse, имя Horse, скорость 0.6303306836602167 +2023-01-23 21:36:33,925 DEBUG Horse Создание Horse, имя Horse, скорость 0.6598296844232557 +2023-01-23 21:36:33,925 DEBUG Horse Создание Horse, имя Horse, скорость 0.9506544904478381 +2023-01-23 21:36:33,926 DEBUG Horse Создание Horse, имя Horse, скорость 0.6078338359237819 +2023-01-23 21:36:33,926 DEBUG Horse Создание Horse, имя Horse, скорость 0.9937066968724008 +2023-01-23 21:36:33,926 DEBUG Horse Создание Horse, имя Horse, скорость 0.17291377699724453 +2023-01-23 21:36:33,927 DEBUG Horse Создание Horse, имя Horse, скорость 0.9197608569717186 +2023-01-23 21:36:33,927 DEBUG Horse Создание Horse, имя Horse, скорость 0.39142348750622524 +2023-01-23 21:36:33,927 DEBUG Horse Создание Horse, имя Horse, скорость 0.30600190830046115 +2023-01-23 21:36:33,927 DEBUG Horse Создание Horse, имя Horse, скорость 0.26448749884138545 +2023-01-23 21:36:33,928 DEBUG Horse Создание Horse, имя Horse, скорость 0.7368698996309604 +2023-01-23 21:36:33,928 DEBUG Horse Создание Horse, имя Horse, скорость 0.22712554954974662 +2023-01-23 21:36:33,928 DEBUG Horse Создание Horse, имя Horse, скорость 0.5375320951215063 +2023-01-23 21:36:33,929 DEBUG Horse Создание Horse, имя Horse, скорость 0.6831282174689517 +2023-01-23 21:36:33,929 DEBUG Horse Создание Horse, имя Horse, скорость 0.44128564494737577 +2023-01-23 21:36:33,929 DEBUG Horse Создание Horse, имя Horse, скорость 0.35400514708723596 +2023-01-23 21:36:33,929 DEBUG Horse Создание Horse, имя Horse, скорость 0.09204394201249877 +2023-01-23 21:36:33,929 DEBUG Horse Создание Horse, имя Horse, скорость 0.8163041089517054 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.6746622436796472 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.008825241739211953 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.638709086637461 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.6797320166077224 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.43539162273187204 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.713286581894386 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.42269491110084867 +2023-01-23 21:36:33,930 DEBUG Horse Создание Horse, имя Horse, скорость 0.02691366933446837 +2023-01-23 21:36:33,931 DEBUG Horse Создание Horse, имя Horse, скорость 0.610396284776596 +2023-01-23 21:36:33,931 DEBUG Horse Создание Horse, имя Horse, скорость 0.26152427505107523 +2023-01-23 21:36:33,931 DEBUG Horse Создание Horse, имя Horse, скорость 0.7144681052093862 +2023-01-23 21:36:33,931 DEBUG Hippodrome Создание Hippodrome, лошадей 30 diff --git a/pom.xml b/pom.xml index a0a25572..693e5f3d 100644 --- a/pom.xml +++ b/pom.xml @@ -14,7 +14,56 @@ - + + org.junit.jupiter + junit-jupiter-api + 5.9.0 + test + + + org.junit.jupiter + junit-jupiter-params + 5.8.2 + test + + + org.mockito + mockito-core + 4.11.0 + test + + + org.mockito + mockito-junit-jupiter + 4.2.0 + test + + + org.mockito + mockito-inline + 4.2.0 + test + + + org.apache.logging.log4j + log4j-api + 2.19.0 + + + org.apache.logging.log4j + log4j-core + 2.19.0 + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.19.0 + + + org.slf4j + slf4j-api + 1.7.36 + \ No newline at end of file diff --git a/src/main/java/Hippodrome.java b/src/main/java/Hippodrome.java index f1a4abb2..261e40e9 100644 --- a/src/main/java/Hippodrome.java +++ b/src/main/java/Hippodrome.java @@ -1,3 +1,6 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -6,16 +9,20 @@ public class Hippodrome { + private static final Logger logger = LoggerFactory.getLogger(Hippodrome.class); + private final List horses; public Hippodrome(List horses) { if (isNull(horses)) { + logger.error("Horses list is null"); throw new IllegalArgumentException("Horses cannot be null."); } else if (horses.isEmpty()) { + logger.error("Horses list is empty"); throw new IllegalArgumentException("Horses cannot be empty."); } - this.horses = horses; + logger.debug("Создание Hippodrome, лошадей {}", horses.size()); } public List getHorses() { diff --git a/src/main/java/Horse.java b/src/main/java/Horse.java index dbf05c34..5177ddc4 100644 --- a/src/main/java/Horse.java +++ b/src/main/java/Horse.java @@ -1,27 +1,37 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import static java.util.Objects.isNull; public class Horse { + private static final Logger logger = LoggerFactory.getLogger(Horse.class); + private final String name; private final double speed; private double distance; public Horse(String name, double speed, double distance) { if (isNull(name)) { + logger.error("Name is null"); throw new IllegalArgumentException("Name cannot be null."); } else if (name.isBlank()) { + logger.error("Name is blank"); throw new IllegalArgumentException("Name cannot be blank."); } if (speed < 0) { + logger.error("Speed is negative"); throw new IllegalArgumentException("Speed cannot be negative."); } if (distance < 0) { + logger.error("Distance is negative"); throw new IllegalArgumentException("Distance cannot be negative."); } this.name = name; this.speed = speed; this.distance = distance; + logger.debug("Создание Horse, имя {}, скорость {}", name, speed); } public Horse(String name, double speed) { diff --git a/src/main/java/Main.java b/src/main/java/Main.java index 89417f76..63d1ca3f 100644 --- a/src/main/java/Main.java +++ b/src/main/java/Main.java @@ -1,9 +1,15 @@ +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.List; import java.util.concurrent.TimeUnit; public class Main { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + public static void main(String[] args) throws Exception { + List horses = List.of( new Horse("Буцефал", 2.4), new Horse("Туз Пик", 2.5), @@ -14,7 +20,7 @@ public static void main(String[] args) throws Exception { new Horse("Вишня", 3) ); Hippodrome hippodrome = new Hippodrome(horses); - + logger.info("Начало скачек. Количество участников: {}", hippodrome.getHorses().size()); for (int i = 0; i < 100; i++) { hippodrome.move(); watch(hippodrome); @@ -23,6 +29,7 @@ public static void main(String[] args) throws Exception { String winnerName = hippodrome.getWinner().getName(); System.out.println("Победил " + winnerName + "!"); + logger.info("Окончание скачек. Победитель: {}", winnerName); } private static void watch(Hippodrome hippodrome) throws Exception { diff --git a/src/main/resources/log4j2.xml b/src/main/resources/log4j2.xml new file mode 100644 index 00000000..57146986 --- /dev/null +++ b/src/main/resources/log4j2.xml @@ -0,0 +1,29 @@ + + + + + + %d %p %c{1.} %m%n + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/test/java/HippodromeTest.java b/src/test/java/HippodromeTest.java new file mode 100644 index 00000000..6da8f4d0 --- /dev/null +++ b/src/test/java/HippodromeTest.java @@ -0,0 +1,78 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +@ExtendWith(MockitoExtension.class) +class HippodromeTest { + + @Test + void hippodromeConstructorParameterIsNullShouldTrowIllegalArgumentExceptionWithMessageHorsesCannotBeNull() { + String message = "Horses cannot be null."; + Throwable exception = assertThrows( + IllegalArgumentException.class, + () -> new Hippodrome(null) + ); + String expected = message; + String actual = exception.getMessage(); + assertEquals(expected, actual); + + } + + @Test + void hippodromeConstructorParameterIsEmptyShouldTrowIllegalArgumentExceptionWithMessageHorsesCannotBeEmpty() { + String message = "Horses cannot be empty."; + Throwable exception = assertThrows( + IllegalArgumentException.class, + () -> new Hippodrome(new ArrayList<>()) + ); + String expected = message; + String actual = exception.getMessage(); + assertEquals(expected, actual); + } + + @Test + void getHorsesShouldReturnListHorsesParameterOfConstructor() { + List horses = new ArrayList<>(); + for (int i = 0; i < 30; i++) { + horses.add(new Horse(Horse.class.getName(), Math.random(), Math.random())); + } + Hippodrome hippodrome = new Hippodrome(horses); + boolean expected = horses.equals(hippodrome.getHorses()); + assertTrue(expected); + } + + @Test + void moveShouldToBeCalledFromAllHorses() { + List horses = new ArrayList<>(); + for (int i = 0; i < 50; i++) { + horses.add(mock(Horse.class)); + } + Hippodrome hippodrome = new Hippodrome(horses); + hippodrome.move(); + for (Horse hors : horses) { + verify(hors).move(); + } + } + + @Test + void getWinnerShouldReturnHorseWithGreatestDistance() { + List horses = new ArrayList<>(); + for (int i = 0; i < 30; i++) { + horses.add(new Horse(Horse.class.getName(), Math.random(), Math.random())); + } + Hippodrome hippodrome = new Hippodrome(horses); + double expected = horses.stream().max(Comparator.comparingDouble(Horse::getDistance)).get().getDistance(); + double actual = hippodrome.getWinner().getDistance(); + assertEquals(expected, actual); + } +} \ No newline at end of file diff --git a/src/test/java/HorseTest.java b/src/test/java/HorseTest.java new file mode 100644 index 00000000..1d539a24 --- /dev/null +++ b/src/test/java/HorseTest.java @@ -0,0 +1,136 @@ +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.MockedStatic; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.only; + +class HorseTest { + @Test + void horseConstructorNameIsNullShouldTrowIllegalArgumentException() { + Class expected = IllegalArgumentException.class; + assertThrows(expected, () -> new Horse(null, 0, 0)); + } + + @Test + void horseConstructorNameIsNullShouldSendMessageNameCannotBeNull() { + String expected = "Name cannot be null."; + try { + new Horse(null, 0, 0); + } catch (IllegalArgumentException exception) { + String actual = exception.getMessage(); + assertEquals(expected, actual); + } + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "\n", "\t"}) + void horseConstructorNameIsBlankShouldTrowIllegalArgumentException(String name) { + Class expected = IllegalArgumentException.class; + assertThrows(expected, () -> new Horse(name, 0, 0)); + } + + @ParameterizedTest + @ValueSource(strings = {"", " ", "\n", "\t"}) + void horseConstructorNameIsBlankShouldSendMessageNameCannotBeBlank(String name) { + String expected = "Name cannot be blank."; + try { + new Horse(name, 0, 0); + } catch (IllegalArgumentException exception) { + String actual = exception.getMessage(); + assertEquals(expected, actual); + } + } + + @Test() + void horseConstructorSpeedIsNegativeShouldTrowIllegalArgumentException() { + Class expected = IllegalArgumentException.class; + assertThrows(expected, () -> new Horse("name", -1, 0)); + } + + @Test + void horseConstructorSpeedIsNegativeShouldSendMessageSpeedCannotBeNegative() { + String expected = "Speed cannot be negative."; + try { + new Horse("name", -1, 0); + } catch (IllegalArgumentException exception) { + String actual = exception.getMessage(); + assertEquals(expected, actual); + } + } + + @Test + void horseConstructorDistanceIsNegativeShouldTrowIllegalArgumentException() { + Class expected = IllegalArgumentException.class; + assertThrows(expected, () -> new Horse("name", 0, -1)); + } + + @Test + void horseConstructorDistanceIsNegativeShouldSendMessageDistanceCannotBeNegative() { + String expected = "Distance cannot be negative."; + try { + new Horse("name", 0, -1); + } catch (IllegalArgumentException exception) { + String actual = exception.getMessage(); + assertEquals(expected, actual); + } + } + + @Test + void getNameShouldReturnName() { + String name = "name"; + Horse horse = new Horse(name, 0, 0); + String expected = name; + String actual = horse.getName(); + assertEquals(expected, actual); + } + + @Test + void getSpeedShouldReturnSpeed() { + double speed = 0; + Horse horse = new Horse("name", speed, 0); + double expected = speed; + double actual = horse.getSpeed(); + assertEquals(expected, actual); + } + + @Test + void getDistanceShouldReturnDistance() { + double distance = 0; + Horse horse = new Horse("name", 0, distance); + double expected = distance; + double actual = horse.getDistance(); + assertEquals(expected, actual); + } + + @Test + void getDistanceShouldReturnZero() { + Horse horse = new Horse("name", 0); + double expected = 0; + double actual = horse.getDistance(); + assertEquals(expected, actual); + } + + @Test + void moveShouldToCallGetRandomDouble() { + try (MockedStatic horseMockedStatic = mockStatic(Horse.class)) { + new Horse("name", 0, 0).move(); + horseMockedStatic.verify(() -> Horse.getRandomDouble(0.2, 0.9), only()); + } + } + + @ParameterizedTest + @ValueSource(doubles = {1.0, 2.0, 3.0}) + void moveShouldAssignValueToDistanceField(double value) { + try (MockedStatic horseMockedStatic = mockStatic(Horse.class)) { + horseMockedStatic.when(() -> Horse.getRandomDouble(0.2, 0.9)).thenReturn(value); + Horse horse = new Horse("name", 1, 0); + horse.move(); + double expected = horse.getDistance(); + assertEquals(expected, Horse.getRandomDouble(0.2, 0.9)); + } + } +} \ No newline at end of file diff --git a/src/test/java/MainTest.java b/src/test/java/MainTest.java new file mode 100644 index 00000000..ce2aedc2 --- /dev/null +++ b/src/test/java/MainTest.java @@ -0,0 +1,12 @@ +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.Timeout; + +class MainTest { + @Test + @Disabled("If necessary, run manually") + @Timeout(value = 22) + void mainRunsForNoMoreThan22Seconds() throws Exception { + Main.main(new String[0]); + } +} \ No newline at end of file