From aac6e14aaff8ab852d5aa19bd1d986ec452267fe Mon Sep 17 00:00:00 2001 From: Srltas Date: Sat, 14 Sep 2024 02:25:18 +0900 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=EB=8F=99=EB=84=A4=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EB=8F=84=EB=A9=94=EC=9D=B8,=20=EC=9C=A0=EC=A6=88?= =?UTF-8?q?=EC=BC=80=EC=9D=B4=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다양한 거리 계산 방법에 대응할 수 있도록 'DistanceCalculator' 인터페이스 도입 - 'Neighborhood'가 자신의 범위를 확인할 수 있도록 비즈니스 로직을 내부에 포함 - 동네가 없거나 범위 밖인 경우를 처리하기 위해 커스텀 예외 생성 --- .../out/HaversineDistanceCalculator.java | 23 ++++++++++++++ .../NeighborhoodVerificationService.java | 31 +++++++++++++++++++ .../NeighborhoodNotFoundException.java | 8 +++++ .../OutOfNeighborhoodBoundaryException.java | 8 +++++ .../model/location/DistanceCalculator.java | 5 +++ .../domain/model/location/Location.java | 19 ++++++++++++ .../model/neighborhood/Neighborhood.java | 26 ++++++++++++++++ .../neighborhood/NeighborhoodRepository.java | 7 +++++ .../VerifiedNeighborhoodRepository.java | 7 +++++ .../runtogether/domain/model/user/User.java | 5 +++ 10 files changed, 139 insertions(+) create mode 100644 src/main/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculator.java create mode 100644 src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java create mode 100644 src/main/java/com/srltas/runtogether/domain/exception/NeighborhoodNotFoundException.java create mode 100644 src/main/java/com/srltas/runtogether/domain/exception/OutOfNeighborhoodBoundaryException.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/location/DistanceCalculator.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/location/Location.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodRepository.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/user/User.java diff --git a/src/main/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculator.java b/src/main/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculator.java new file mode 100644 index 0000000..62a5054 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculator.java @@ -0,0 +1,23 @@ +package com.srltas.runtogether.adapter.out; + +import com.srltas.runtogether.domain.model.location.DistanceCalculator; +import com.srltas.runtogether.domain.model.location.Location; + +public class HaversineDistanceCalculator implements DistanceCalculator { + + private static final double EARTH_RADIUS_KM = 6371; + + @Override + public double calculateDistanceBetween(Location location1, Location location2) { + double latitude = Math.toRadians(location1.getLatitude() - location2.getLatitude()); + double longitude = Math.toRadians(location1.getLongitude() - location2.getLongitude()); + + double a = Math.sin(latitude / 2) * Math.sin(latitude / 2) + + Math.cos(Math.toRadians(location2.getLatitude())) * Math.cos(Math.toRadians(location1.getLatitude())) + * Math.sin(longitude / 2) * Math.sin(longitude / 2); + + double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + + return EARTH_RADIUS_KM * c; + } +} diff --git a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java new file mode 100644 index 0000000..d67e99a --- /dev/null +++ b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java @@ -0,0 +1,31 @@ +package com.srltas.runtogether.application; + +import com.srltas.runtogether.domain.exception.NeighborhoodNotFoundException; +import com.srltas.runtogether.domain.exception.OutOfNeighborhoodBoundaryException; +import com.srltas.runtogether.domain.model.location.DistanceCalculator; +import com.srltas.runtogether.domain.model.location.Location; +import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; +import com.srltas.runtogether.domain.model.neighborhood.NeighborhoodRepository; +import com.srltas.runtogether.domain.model.neighborhood.VerifiedNeighborhoodRepository; +import com.srltas.runtogether.domain.model.user.User; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class NeighborhoodVerificationService { + + private final NeighborhoodRepository neighborhoodRepository; + private final VerifiedNeighborhoodRepository verifiedNeighborhoodRepository; + private final DistanceCalculator distanceCalculator; + + public void verifyAndRegisterNeighborhood(User user, Location currentLocation, String neighborhoodName) { + Neighborhood neighborhood = neighborhoodRepository.findByName(neighborhoodName) + .orElseThrow(() -> new NeighborhoodNotFoundException(neighborhoodName)); + + if (neighborhood.isWithinBoundary(currentLocation, distanceCalculator)) { + verifiedNeighborhoodRepository.saveVerifiedNeighborhood(user, neighborhood); + } else { + throw new OutOfNeighborhoodBoundaryException(neighborhoodName); + } + } +} diff --git a/src/main/java/com/srltas/runtogether/domain/exception/NeighborhoodNotFoundException.java b/src/main/java/com/srltas/runtogether/domain/exception/NeighborhoodNotFoundException.java new file mode 100644 index 0000000..65cbf91 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/exception/NeighborhoodNotFoundException.java @@ -0,0 +1,8 @@ +package com.srltas.runtogether.domain.exception; + +public class NeighborhoodNotFoundException extends RuntimeException { + + public NeighborhoodNotFoundException(String neighborhoodName) { + super(String.format("Neighborhood not found: %s", neighborhoodName)); + } +} diff --git a/src/main/java/com/srltas/runtogether/domain/exception/OutOfNeighborhoodBoundaryException.java b/src/main/java/com/srltas/runtogether/domain/exception/OutOfNeighborhoodBoundaryException.java new file mode 100644 index 0000000..d64d4f6 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/exception/OutOfNeighborhoodBoundaryException.java @@ -0,0 +1,8 @@ +package com.srltas.runtogether.domain.exception; + +public class OutOfNeighborhoodBoundaryException extends RuntimeException { + + public OutOfNeighborhoodBoundaryException(String neighborhoodName) { + super(String.format("User is outside of the boundary of neighborhood: %s", neighborhoodName)); + } +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/location/DistanceCalculator.java b/src/main/java/com/srltas/runtogether/domain/model/location/DistanceCalculator.java new file mode 100644 index 0000000..e5ec43c --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/location/DistanceCalculator.java @@ -0,0 +1,5 @@ +package com.srltas.runtogether.domain.model.location; + +public interface DistanceCalculator { + double calculateDistanceBetween(Location location1, Location location2); +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/location/Location.java b/src/main/java/com/srltas/runtogether/domain/model/location/Location.java new file mode 100644 index 0000000..8b20089 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/location/Location.java @@ -0,0 +1,19 @@ +package com.srltas.runtogether.domain.model.location; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@Getter +@EqualsAndHashCode +@AllArgsConstructor +public class Location { + + private final double latitude; + private final double longitude; + + public double calculateDistance(Location otherLocation, DistanceCalculator distanceCalculator) { + return distanceCalculator.calculateDistanceBetween(otherLocation, this); + } +} + diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java new file mode 100644 index 0000000..ead5d82 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java @@ -0,0 +1,26 @@ +package com.srltas.runtogether.domain.model.neighborhood; + +import com.srltas.runtogether.domain.model.location.DistanceCalculator; +import com.srltas.runtogether.domain.model.location.Location; + +import lombok.AllArgsConstructor; +import lombok.EqualsAndHashCode; +import lombok.Getter; + +@EqualsAndHashCode +@AllArgsConstructor +public class Neighborhood { + + @Getter + private final String name; + + @Getter + private final Location location; + + private final double boundaryRadius; + + public boolean isWithinBoundary(Location currentLocation, DistanceCalculator distanceCalculator) { + double distance = location.calculateDistance(currentLocation, distanceCalculator); + return distance <= boundaryRadius; + } +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodRepository.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodRepository.java new file mode 100644 index 0000000..c1fd52c --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodRepository.java @@ -0,0 +1,7 @@ +package com.srltas.runtogether.domain.model.neighborhood; + +import java.util.Optional; + +public interface NeighborhoodRepository { + Optional findByName(String name); +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java new file mode 100644 index 0000000..8be9c5a --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java @@ -0,0 +1,7 @@ +package com.srltas.runtogether.domain.model.neighborhood; + +import com.srltas.runtogether.domain.model.user.User; + +public interface VerifiedNeighborhoodRepository { + void saveVerifiedNeighborhood(User user, Neighborhood neighborhood); +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/user/User.java b/src/main/java/com/srltas/runtogether/domain/model/user/User.java new file mode 100644 index 0000000..95277c2 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/user/User.java @@ -0,0 +1,5 @@ +package com.srltas.runtogether.domain.model.user; + +public class User { + //TODO TBD +} From 161c536114cb1d564eae2736596d84d644d333bc Mon Sep 17 00:00:00 2001 From: Srltas Date: Sat, 14 Sep 2024 02:27:29 +0900 Subject: [PATCH 2/7] =?UTF-8?q?feat:=20=EB=8F=99=EB=84=A4=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../out/HaversineDistanceCalculatorTest.java | 31 +++++++ .../NeighborhoodVerificationServiceTest.java | 82 +++++++++++++++++++ .../model/neighborhood/NeighborhoodTest.java | 51 ++++++++++++ 3 files changed, 164 insertions(+) create mode 100644 src/test/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculatorTest.java create mode 100644 src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java create mode 100644 src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java diff --git a/src/test/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculatorTest.java b/src/test/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculatorTest.java new file mode 100644 index 0000000..e1abfe1 --- /dev/null +++ b/src/test/java/com/srltas/runtogether/adapter/out/HaversineDistanceCalculatorTest.java @@ -0,0 +1,31 @@ +package com.srltas.runtogether.adapter.out; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.api.Test; + +import com.srltas.runtogether.domain.model.location.Location; + +class HaversineDistanceCalculatorTest { + + private final HaversineDistanceCalculator haversineDistanceCalculator = new HaversineDistanceCalculator(); + + private final Location seoul = new Location(37.566535, 126.977969); + private final Location busan = new Location(35.179554, 129.075641); + + @Test + public void testCalculateDistanceBetween_TwoLocations() { + double seoulBusanDistance = 325.0; + + double distance = haversineDistanceCalculator.calculateDistanceBetween(seoul, busan); + + assertEquals(seoulBusanDistance, distance, 1.0); + } + + @Test + public void testCalculateDistanceBetween_SameLocation() { + double distance = haversineDistanceCalculator.calculateDistanceBetween(seoul, seoul); + + assertEquals(0.0, distance); + } +} \ No newline at end of file diff --git a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java new file mode 100644 index 0000000..0b4cf67 --- /dev/null +++ b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java @@ -0,0 +1,82 @@ +package com.srltas.runtogether.application; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.*; + +import java.util.Optional; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; + +import com.srltas.runtogether.domain.exception.NeighborhoodNotFoundException; +import com.srltas.runtogether.domain.exception.OutOfNeighborhoodBoundaryException; +import com.srltas.runtogether.domain.model.location.DistanceCalculator; +import com.srltas.runtogether.domain.model.location.Location; +import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; +import com.srltas.runtogether.domain.model.neighborhood.NeighborhoodRepository; +import com.srltas.runtogether.domain.model.neighborhood.VerifiedNeighborhoodRepository; +import com.srltas.runtogether.domain.model.user.User; + +class NeighborhoodVerificationServiceTest { + + @Mock + private NeighborhoodRepository neighborhoodRepository; + + @Mock + private VerifiedNeighborhoodRepository verifiedNeighborhoodRepository; + + @Mock + private DistanceCalculator distanceCalculator; + + @InjectMocks + private NeighborhoodVerificationService neighborhoodVerificationService; + + private User user = new User(); + private String neighborhoodName = "Gangnam"; + private Location currentLocation = new Location(37.505858, 127.058319); + private Neighborhood neighborhood = new Neighborhood(neighborhoodName, new Location(37.517347, 127.047382), 7.0); + + @BeforeEach + public void setUp() { + openMocks(this); + } + + @Test + public void testVerifyAndRegisterNeighborhood_WithinBoundary() { + when(neighborhoodRepository.findByName(neighborhoodName)).thenReturn(Optional.of(neighborhood)); + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())).thenReturn(5.0); + + neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + + verify(verifiedNeighborhoodRepository).saveVerifiedNeighborhood(user, neighborhood); + } + + @Test + public void testVerifyAndRegisterNeighborhood_OutsideBoundary() { + when(neighborhoodRepository.findByName(neighborhoodName)).thenReturn(Optional.of(neighborhood)); + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())).thenReturn(15.0); + + OutOfNeighborhoodBoundaryException exception = assertThrows(OutOfNeighborhoodBoundaryException.class, () -> { + neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + }); + + assertEquals(String.format("User is outside of the boundary of neighborhood: %s", neighborhoodName), + exception.getMessage()); + verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + } + + @Test + public void testVerifyAndRegisterNeighborhood_NeighborhoodNotFound() { + when(neighborhoodRepository.findByName("Homaesil")).thenReturn(Optional.empty()); + + NeighborhoodNotFoundException exception = assertThrows(NeighborhoodNotFoundException.class, () -> { + neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + }); + + assertEquals(String.format("Neighborhood not found: %s", neighborhoodName), exception.getMessage()); + verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + } +} \ No newline at end of file diff --git a/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java b/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java new file mode 100644 index 0000000..a08483d --- /dev/null +++ b/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java @@ -0,0 +1,51 @@ +package com.srltas.runtogether.domain.model.neighborhood; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; +import static org.mockito.MockitoAnnotations.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +import com.srltas.runtogether.domain.model.location.DistanceCalculator; +import com.srltas.runtogether.domain.model.location.Location; + +class NeighborhoodTest { + + @Mock + private DistanceCalculator distanceCalculator; + + private Location currentLocation; + private Location neighborhoodLocation; + private Neighborhood neighborhood; + + @BeforeEach + public void setUp() { + openMocks(this); + + currentLocation = new Location(37.505858, 127.058319); + neighborhoodLocation = new Location(37.517347, 127.047382); + neighborhood = new Neighborhood("Gangnam", neighborhoodLocation, 7.0); + } + + @Test + public void testIsWithinBoundary_WhenUserInSideBoundary() { + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhoodLocation)).thenReturn(5.0); + + boolean isInSide = neighborhood.isWithinBoundary(currentLocation, distanceCalculator); + + assertTrue(isInSide); + verify(distanceCalculator).calculateDistanceBetween(currentLocation, neighborhoodLocation); + } + + @Test + public void testIsWithinBoundary_WhenUserOutsideBoundary() { + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhoodLocation)).thenReturn(10.0); + + boolean isInSide = neighborhood.isWithinBoundary(currentLocation, distanceCalculator); + + assertFalse(isInSide); + verify(distanceCalculator).calculateDistanceBetween(currentLocation, neighborhoodLocation); + } +} \ No newline at end of file From 3d9ea41651c5825e386b1d96fdc85f9b0cf7370c Mon Sep 17 00:00:00 2001 From: Dongmin Kim <49967405+Srltas@users.noreply.github.com> Date: Sun, 15 Sep 2024 00:31:49 +0900 Subject: [PATCH 3/7] =?UTF-8?q?[#13]=20Lombok=20=EB=9D=BC=EC=9D=B4?= =?UTF-8?q?=EB=B8=8C=EB=9F=AC=EB=A6=AC=20=EC=B6=94=EA=B0=80=20(#14)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/build.gradle b/build.gradle index 1c94e37..b050034 100644 --- a/build.gradle +++ b/build.gradle @@ -21,6 +21,13 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // Lombok + compileOnly 'org.projectlombok:lombok:1.18.34' + annotationProcessor 'org.projectlombok:lombok:1.18.34' + + testCompileOnly 'org.projectlombok:lombok:1.18.34' + testAnnotationProcessor 'org.projectlombok:lombok:1.18.34' } tasks.named('test') { From b66f2c75d43cefc2931f5271ca95f94e97f3ba55 Mon Sep 17 00:00:00 2001 From: Srltas Date: Sun, 15 Sep 2024 16:38:58 +0900 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20RequiredArgsConstructor?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Lombok의 AllArgsConstructor 어노테이션을 RequiredArgsConstructor로 변경 --- .../application/NeighborhoodVerificationService.java | 4 ++-- .../srltas/runtogether/domain/model/location/Location.java | 4 ++-- .../runtogether/domain/model/neighborhood/Neighborhood.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java index d67e99a..1330c71 100644 --- a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java +++ b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java @@ -9,9 +9,9 @@ import com.srltas.runtogether.domain.model.neighborhood.VerifiedNeighborhoodRepository; import com.srltas.runtogether.domain.model.user.User; -import lombok.AllArgsConstructor; +import lombok.RequiredArgsConstructor; -@AllArgsConstructor +@RequiredArgsConstructor public class NeighborhoodVerificationService { private final NeighborhoodRepository neighborhoodRepository; diff --git a/src/main/java/com/srltas/runtogether/domain/model/location/Location.java b/src/main/java/com/srltas/runtogether/domain/model/location/Location.java index 8b20089..29354c8 100644 --- a/src/main/java/com/srltas/runtogether/domain/model/location/Location.java +++ b/src/main/java/com/srltas/runtogether/domain/model/location/Location.java @@ -1,12 +1,12 @@ package com.srltas.runtogether.domain.model.location; -import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.RequiredArgsConstructor; @Getter @EqualsAndHashCode -@AllArgsConstructor +@RequiredArgsConstructor public class Location { private final double latitude; diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java index ead5d82..ea1ce46 100644 --- a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java +++ b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java @@ -3,12 +3,12 @@ import com.srltas.runtogether.domain.model.location.DistanceCalculator; import com.srltas.runtogether.domain.model.location.Location; -import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.RequiredArgsConstructor; @EqualsAndHashCode -@AllArgsConstructor +@RequiredArgsConstructor public class Neighborhood { @Getter From e24cc0026e0ad7a14690dea3187fd4ecb5a14b65 Mon Sep 17 00:00:00 2001 From: Srltas Date: Wed, 18 Sep 2024 23:17:02 +0900 Subject: [PATCH 5/7] =?UTF-8?q?test:=20=EB=8F=99=EB=84=A4=20=EC=9D=B8?= =?UTF-8?q?=EC=A6=9D=20=EC=9C=A0=EC=A6=88=EC=BC=80=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nested 애노테이션을 이용해 테스트 목적에 따라 분리 --- .../NeighborhoodVerificationServiceTest.java | 65 ++++++++++++------- 1 file changed, 40 insertions(+), 25 deletions(-) diff --git a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java index 0b4cf67..f2c9a1a 100644 --- a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java +++ b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java @@ -1,5 +1,6 @@ package com.srltas.runtogether.application; +import static java.lang.String.format; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.*; @@ -7,6 +8,7 @@ import java.util.Optional; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; @@ -44,39 +46,52 @@ public void setUp() { openMocks(this); } - @Test - public void testVerifyAndRegisterNeighborhood_WithinBoundary() { - when(neighborhoodRepository.findByName(neighborhoodName)).thenReturn(Optional.of(neighborhood)); - when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())).thenReturn(5.0); + @Nested + class WhenNeighborhoodIsFound { - neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + @BeforeEach + public void setUp() { + when(neighborhoodRepository.findByName(neighborhoodName)).thenReturn(Optional.of(neighborhood)); + } - verify(verifiedNeighborhoodRepository).saveVerifiedNeighborhood(user, neighborhood); - } - - @Test - public void testVerifyAndRegisterNeighborhood_OutsideBoundary() { - when(neighborhoodRepository.findByName(neighborhoodName)).thenReturn(Optional.of(neighborhood)); - when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())).thenReturn(15.0); + @Test + public void testVerifyAndRegisterNeighborhood_WithinBoundary() { + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())) + .thenReturn(5.0); - OutOfNeighborhoodBoundaryException exception = assertThrows(OutOfNeighborhoodBoundaryException.class, () -> { neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); - }); - assertEquals(String.format("User is outside of the boundary of neighborhood: %s", neighborhoodName), - exception.getMessage()); - verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + verify(verifiedNeighborhoodRepository).saveVerifiedNeighborhood(user, neighborhood); + } + + @Test + public void testVerifyAndRegisterNeighborhood_OutsideBoundary() { + when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhood.getLocation())) + .thenReturn(15.0); + + OutOfNeighborhoodBoundaryException exception = assertThrows(OutOfNeighborhoodBoundaryException.class, + () -> { + neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + }); + + assertEquals(format("User is outside of the boundary of neighborhood: %s", neighborhoodName), exception.getMessage()); + verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + } } - @Test - public void testVerifyAndRegisterNeighborhood_NeighborhoodNotFound() { - when(neighborhoodRepository.findByName("Homaesil")).thenReturn(Optional.empty()); + @Nested + class WhenNeighborhoodIsNotFound { + @Test + public void testVerifyAndRegisterNeighborhood_NeighborhoodNotFound() { + when(neighborhoodRepository.findByName("Homaesil")).thenReturn(Optional.empty()); - NeighborhoodNotFoundException exception = assertThrows(NeighborhoodNotFoundException.class, () -> { - neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); - }); + NeighborhoodNotFoundException exception = assertThrows(NeighborhoodNotFoundException.class, + () -> { + neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); + }); - assertEquals(String.format("Neighborhood not found: %s", neighborhoodName), exception.getMessage()); - verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + assertEquals(format("Neighborhood not found: %s", neighborhoodName), exception.getMessage()); + verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + } } } \ No newline at end of file From 44fbaaed13708e8c87a7229027e5b808b9c79de2 Mon Sep 17 00:00:00 2001 From: Srltas Date: Fri, 20 Sep 2024 22:44:49 +0900 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20=EA=B1=B0=EB=A6=AC=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=EC=9D=84=20Neighborhood=20=EB=82=B4=EB=B6=80=EB=A1=9C?= =?UTF-8?q?=20=EC=BA=A1=EC=8A=90=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 캡슐화와 코드의 응집도를 높이기 위한 수정입니다 - Neighborhood를 생성할 때 distanceCalculator를 주입 받습니다 - NeighborhoodVerificationService 유즈케이스에서 더 이상 distanceCalculator에 대해 알 필요가 없습니다 --- .../application/NeighborhoodVerificationService.java | 4 +--- .../runtogether/domain/model/neighborhood/Neighborhood.java | 4 +++- .../application/NeighborhoodVerificationServiceTest.java | 3 ++- .../domain/model/neighborhood/NeighborhoodTest.java | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java index 1330c71..078fcea 100644 --- a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java +++ b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java @@ -2,7 +2,6 @@ import com.srltas.runtogether.domain.exception.NeighborhoodNotFoundException; import com.srltas.runtogether.domain.exception.OutOfNeighborhoodBoundaryException; -import com.srltas.runtogether.domain.model.location.DistanceCalculator; import com.srltas.runtogether.domain.model.location.Location; import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; import com.srltas.runtogether.domain.model.neighborhood.NeighborhoodRepository; @@ -16,13 +15,12 @@ public class NeighborhoodVerificationService { private final NeighborhoodRepository neighborhoodRepository; private final VerifiedNeighborhoodRepository verifiedNeighborhoodRepository; - private final DistanceCalculator distanceCalculator; public void verifyAndRegisterNeighborhood(User user, Location currentLocation, String neighborhoodName) { Neighborhood neighborhood = neighborhoodRepository.findByName(neighborhoodName) .orElseThrow(() -> new NeighborhoodNotFoundException(neighborhoodName)); - if (neighborhood.isWithinBoundary(currentLocation, distanceCalculator)) { + if (neighborhood.isWithinBoundary(currentLocation)) { verifiedNeighborhoodRepository.saveVerifiedNeighborhood(user, neighborhood); } else { throw new OutOfNeighborhoodBoundaryException(neighborhoodName); diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java index ea1ce46..ffead22 100644 --- a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java +++ b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/Neighborhood.java @@ -19,7 +19,9 @@ public class Neighborhood { private final double boundaryRadius; - public boolean isWithinBoundary(Location currentLocation, DistanceCalculator distanceCalculator) { + private final DistanceCalculator distanceCalculator; + + public boolean isWithinBoundary(Location currentLocation) { double distance = location.calculateDistance(currentLocation, distanceCalculator); return distance <= boundaryRadius; } diff --git a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java index f2c9a1a..b5a83a2 100644 --- a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java +++ b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java @@ -39,11 +39,12 @@ class NeighborhoodVerificationServiceTest { private User user = new User(); private String neighborhoodName = "Gangnam"; private Location currentLocation = new Location(37.505858, 127.058319); - private Neighborhood neighborhood = new Neighborhood(neighborhoodName, new Location(37.517347, 127.047382), 7.0); + private Neighborhood neighborhood; @BeforeEach public void setUp() { openMocks(this); + neighborhood = new Neighborhood(neighborhoodName, new Location(37.517347, 127.047382), 7.0, distanceCalculator); } @Nested diff --git a/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java b/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java index a08483d..7675c27 100644 --- a/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java +++ b/src/test/java/com/srltas/runtogether/domain/model/neighborhood/NeighborhoodTest.java @@ -26,14 +26,14 @@ public void setUp() { currentLocation = new Location(37.505858, 127.058319); neighborhoodLocation = new Location(37.517347, 127.047382); - neighborhood = new Neighborhood("Gangnam", neighborhoodLocation, 7.0); + neighborhood = new Neighborhood("Gangnam", neighborhoodLocation, 7.0, distanceCalculator); } @Test public void testIsWithinBoundary_WhenUserInSideBoundary() { when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhoodLocation)).thenReturn(5.0); - boolean isInSide = neighborhood.isWithinBoundary(currentLocation, distanceCalculator); + boolean isInSide = neighborhood.isWithinBoundary(currentLocation); assertTrue(isInSide); verify(distanceCalculator).calculateDistanceBetween(currentLocation, neighborhoodLocation); @@ -43,7 +43,7 @@ public void testIsWithinBoundary_WhenUserInSideBoundary() { public void testIsWithinBoundary_WhenUserOutsideBoundary() { when(distanceCalculator.calculateDistanceBetween(currentLocation, neighborhoodLocation)).thenReturn(10.0); - boolean isInSide = neighborhood.isWithinBoundary(currentLocation, distanceCalculator); + boolean isInSide = neighborhood.isWithinBoundary(currentLocation); assertFalse(isInSide); verify(distanceCalculator).calculateDistanceBetween(currentLocation, neighborhoodLocation); From 41771a9bb3ce670de87b1664edef6ca65e948898 Mon Sep 17 00:00:00 2001 From: Srltas Date: Sat, 21 Sep 2024 01:42:19 +0900 Subject: [PATCH 7/7] =?UTF-8?q?refactor:=20Aggregate=20=ED=8C=A8=ED=84=B4?= =?UTF-8?q?=20=EC=A0=81=EC=9A=A9=EC=9D=84=20=ED=86=B5=ED=95=9C=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 인증된 동네를 관리하기 위해 VerifiedNeighborhood 도메인 생성 - User와 VerifiedNeighborhood를 하나의 애그리게이트로 통합 - User 도메인 내에 verifiedNeighborhood 컬렉션을 추가하여 인증된 동네 관리 --- .../NeighborhoodVerificationService.java | 7 ++++--- .../VerifiedNeighborhoodRepository.java | 7 ------- .../runtogether/domain/model/user/User.java | 17 ++++++++++++++++- .../domain/model/user/UserRepository.java | 5 +++++ .../domain/model/user/VerifiedNeighborhood.java | 16 ++++++++++++++++ .../NeighborhoodVerificationServiceTest.java | 14 +++++++------- 6 files changed, 48 insertions(+), 18 deletions(-) delete mode 100644 src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/user/UserRepository.java create mode 100644 src/main/java/com/srltas/runtogether/domain/model/user/VerifiedNeighborhood.java diff --git a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java index 078fcea..68c273e 100644 --- a/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java +++ b/src/main/java/com/srltas/runtogether/application/NeighborhoodVerificationService.java @@ -5,8 +5,8 @@ import com.srltas.runtogether.domain.model.location.Location; import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; import com.srltas.runtogether.domain.model.neighborhood.NeighborhoodRepository; -import com.srltas.runtogether.domain.model.neighborhood.VerifiedNeighborhoodRepository; import com.srltas.runtogether.domain.model.user.User; +import com.srltas.runtogether.domain.model.user.UserRepository; import lombok.RequiredArgsConstructor; @@ -14,14 +14,15 @@ public class NeighborhoodVerificationService { private final NeighborhoodRepository neighborhoodRepository; - private final VerifiedNeighborhoodRepository verifiedNeighborhoodRepository; + private final UserRepository userRepository; public void verifyAndRegisterNeighborhood(User user, Location currentLocation, String neighborhoodName) { Neighborhood neighborhood = neighborhoodRepository.findByName(neighborhoodName) .orElseThrow(() -> new NeighborhoodNotFoundException(neighborhoodName)); if (neighborhood.isWithinBoundary(currentLocation)) { - verifiedNeighborhoodRepository.saveVerifiedNeighborhood(user, neighborhood); + user.addVerifiedNeighborhood(neighborhood); + userRepository.save(user); } else { throw new OutOfNeighborhoodBoundaryException(neighborhoodName); } diff --git a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java b/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java deleted file mode 100644 index 8be9c5a..0000000 --- a/src/main/java/com/srltas/runtogether/domain/model/neighborhood/VerifiedNeighborhoodRepository.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.srltas.runtogether.domain.model.neighborhood; - -import com.srltas.runtogether.domain.model.user.User; - -public interface VerifiedNeighborhoodRepository { - void saveVerifiedNeighborhood(User user, Neighborhood neighborhood); -} diff --git a/src/main/java/com/srltas/runtogether/domain/model/user/User.java b/src/main/java/com/srltas/runtogether/domain/model/user/User.java index 95277c2..9a60a57 100644 --- a/src/main/java/com/srltas/runtogether/domain/model/user/User.java +++ b/src/main/java/com/srltas/runtogether/domain/model/user/User.java @@ -1,5 +1,20 @@ package com.srltas.runtogether.domain.model.user; +import java.util.ArrayList; +import java.util.List; + +import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; + +import lombok.RequiredArgsConstructor; + +@RequiredArgsConstructor public class User { - //TODO TBD + + private final Long id; + private final String name; + private List verifiedNeighborhoods = new ArrayList<>(); + + public void addVerifiedNeighborhood(Neighborhood neighborhood) { + this.verifiedNeighborhoods.add(new VerifiedNeighborhood(neighborhood)); + } } diff --git a/src/main/java/com/srltas/runtogether/domain/model/user/UserRepository.java b/src/main/java/com/srltas/runtogether/domain/model/user/UserRepository.java new file mode 100644 index 0000000..7258383 --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/user/UserRepository.java @@ -0,0 +1,5 @@ +package com.srltas.runtogether.domain.model.user; + +public interface UserRepository { + void save(User user); +} diff --git a/src/main/java/com/srltas/runtogether/domain/model/user/VerifiedNeighborhood.java b/src/main/java/com/srltas/runtogether/domain/model/user/VerifiedNeighborhood.java new file mode 100644 index 0000000..39401ae --- /dev/null +++ b/src/main/java/com/srltas/runtogether/domain/model/user/VerifiedNeighborhood.java @@ -0,0 +1,16 @@ +package com.srltas.runtogether.domain.model.user; + +import java.time.LocalDateTime; + +import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; + +public class VerifiedNeighborhood { + + private final Neighborhood neighborhood; + private final LocalDateTime verifiedAt; + + public VerifiedNeighborhood(Neighborhood neighborhood) { + this.neighborhood = neighborhood; + this.verifiedAt = LocalDateTime.now(); + } +} diff --git a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java index b5a83a2..a5ffc55 100644 --- a/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java +++ b/src/test/java/com/srltas/runtogether/application/NeighborhoodVerificationServiceTest.java @@ -19,8 +19,8 @@ import com.srltas.runtogether.domain.model.location.Location; import com.srltas.runtogether.domain.model.neighborhood.Neighborhood; import com.srltas.runtogether.domain.model.neighborhood.NeighborhoodRepository; -import com.srltas.runtogether.domain.model.neighborhood.VerifiedNeighborhoodRepository; import com.srltas.runtogether.domain.model.user.User; +import com.srltas.runtogether.domain.model.user.UserRepository; class NeighborhoodVerificationServiceTest { @@ -28,15 +28,15 @@ class NeighborhoodVerificationServiceTest { private NeighborhoodRepository neighborhoodRepository; @Mock - private VerifiedNeighborhoodRepository verifiedNeighborhoodRepository; + private DistanceCalculator distanceCalculator; @Mock - private DistanceCalculator distanceCalculator; + private UserRepository userRepository; @InjectMocks private NeighborhoodVerificationService neighborhoodVerificationService; - private User user = new User(); + private User user = new User(1L, "testUser"); private String neighborhoodName = "Gangnam"; private Location currentLocation = new Location(37.505858, 127.058319); private Neighborhood neighborhood; @@ -62,7 +62,7 @@ public void testVerifyAndRegisterNeighborhood_WithinBoundary() { neighborhoodVerificationService.verifyAndRegisterNeighborhood(user, currentLocation, neighborhoodName); - verify(verifiedNeighborhoodRepository).saveVerifiedNeighborhood(user, neighborhood); + verify(userRepository).save(user); } @Test @@ -76,7 +76,7 @@ public void testVerifyAndRegisterNeighborhood_OutsideBoundary() { }); assertEquals(format("User is outside of the boundary of neighborhood: %s", neighborhoodName), exception.getMessage()); - verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + verify(userRepository, never()).save(user); } } @@ -92,7 +92,7 @@ public void testVerifyAndRegisterNeighborhood_NeighborhoodNotFound() { }); assertEquals(format("Neighborhood not found: %s", neighborhoodName), exception.getMessage()); - verify(verifiedNeighborhoodRepository, never()).saveVerifiedNeighborhood(user, neighborhood); + verify(userRepository, never()).save(user); } } } \ No newline at end of file