가장 흔한 10가지 스프링 프레임워크 실수
게시 됨: 2022-03-11Spring은 틀림없이 가장 인기 있는 Java 프레임워크 중 하나이며 길들일 수 있는 강력한 짐승이기도 합니다. 기본 개념은 상당히 이해하기 쉽지만 강력한 Spring 개발자가 되려면 시간과 노력이 필요합니다.
이 기사에서 우리는 특히 웹 애플리케이션과 Spring Boot를 지향하는 Spring의 일반적인 실수 중 일부를 다룰 것입니다. Spring Boot의 웹 사이트에 나와 있는 것처럼 Spring Boot는 프로덕션 준비 애플리케이션을 구축하는 방법에 대한 견해 를 갖고 있으므로 이 기사에서는 이러한 관점을 모방하고 표준 Spring Boot 웹 애플리케이션 개발에 잘 통합될 몇 가지 팁에 대한 개요를 제공합니다.
Spring Boot에 익숙하지 않지만 언급된 사항 중 일부를 계속 시도하고 싶은 경우를 위해 이 기사와 함께 GitHub 리포지토리를 만들었습니다. 기사 중 어느 시점에서든 길을 잃는다면 저장소를 복제하고 로컬 컴퓨터에서 코드를 가지고 노는 것이 좋습니다.
일반적인 실수 #1: 너무 낮은 수준으로 이동
"여기서 발명되지 않은" 신드롬은 소프트웨어 개발 세계에서 매우 일반적이기 때문에 우리는 이 흔한 실수를 하고 있습니다. 자주 사용하는 코드의 일부를 정기적으로 다시 작성하는 등의 증상과 많은 개발자가 겪고 있는 것 같습니다.
특정 라이브러리와 그 구현의 내부를 이해하는 것이 대부분 좋고 필요하지만(또한 훌륭한 학습 프로세스가 될 수도 있음) 동일한 저수준 구현을 지속적으로 다루는 것은 소프트웨어 엔지니어로서의 개발에 해롭습니다. 세부. Spring과 같은 추상화 및 프레임워크가 존재하는 이유는 반복적인 수동 작업에서 정확히 분리하고 도메인 개체 및 비즈니스 로직과 같은 더 높은 수준의 세부 사항에 집중할 수 있도록 하기 위해서입니다.
따라서 추상화를 수용하십시오. 다음에 특정 문제에 직면했을 때 먼저 빠른 검색을 수행하고 해당 문제를 해결하는 라이브러리가 이미 Spring에 통합되어 있는지 확인하십시오. 요즘에는 적절한 기존 솔루션을 찾을 수 있습니다. 유용한 라이브러리의 예로서 이 기사의 나머지 부분에 대한 예에서 Project Lombok 주석을 사용할 것입니다. Lombok은 상용구 코드 생성기로 사용되며 여러분 내부의 게으른 개발자는 라이브러리에 익숙해지는 데 문제가 없어야 합니다. 예를 들어 Lombok에서 "표준 Java bean"이 어떻게 보이는지 확인하십시오.
@Getter @Setter @NoArgsConstructor public class Bean implements Serializable { int firstBeanProperty; String secondBeanProperty; }
상상할 수 있듯이 위의 코드는 다음과 같이 컴파일됩니다.
public class Bean implements Serializable { private int firstBeanProperty; private String secondBeanProperty; public int getFirstBeanProperty() { return this.firstBeanProperty; } public String getSecondBeanProperty() { return this.secondBeanProperty; } public void setFirstBeanProperty(int firstBeanProperty) { this.firstBeanProperty = firstBeanProperty; } public void setSecondBeanProperty(String secondBeanProperty) { this.secondBeanProperty = secondBeanProperty; } public Bean() { } }
그러나 IDE와 함께 Lombok을 사용하려는 경우 플러그인을 설치해야 할 가능성이 높다는 점에 유의하십시오. IntelliJ IDEA의 플러그인 버전은 여기에서 찾을 수 있습니다.
일반적인 실수 #2: 내부 '누설'
내부 구조를 노출하는 것은 서비스 디자인의 유연성을 높이고 결과적으로 나쁜 코딩 관행을 조장하기 때문에 결코 좋은 생각이 아닙니다. '누설' 내부는 특정 API 끝점에서 데이터베이스 구조에 액세스할 수 있도록 하여 나타납니다. 예를 들어 다음 POJO("Plain Old Java Object")가 데이터베이스의 테이블을 나타낸다고 가정해 보겠습니다.
@Entity @NoArgsConstructor @Getter public class TopTalentEntity { @Id @GeneratedValue private Integer id; @Column private String name; public TopTalentEntity(String name) { this.name = name; } }
TopTalentEntity
데이터에 액세스해야 하는 엔드포인트가 있다고 가정해 보겠습니다. TopTalentEntity
인스턴스를 반환하고 싶을 수 있으므로 보다 유연한 솔루션은 API 끝점에서 TopTalentEntity
데이터를 나타내는 새 클래스를 만드는 것입니다.
@AllArgsConstructor @NoArgsConstructor @Getter public class TopTalentData { private String name; }
그렇게 하면 데이터베이스 백엔드를 변경할 때 서비스 계층을 추가로 변경할 필요가 없습니다. 사용자의 비밀번호 해시를 데이터베이스에 저장하기 위해 TopTalentEntity
에 '비밀번호' 필드를 추가하는 경우에 어떤 일이 일어날지 생각해 보십시오. TopTalentData
와 같은 커넥터 없이 서비스 프론트엔드 변경을 잊어버리면 매우 바람직하지 않은 비밀 정보가 실수로 노출될 것입니다. !
일반적인 실수 #3: 관심사 분리 부족
애플리케이션이 성장함에 따라 코드 구성이 점점 더 중요한 문제가 되기 시작합니다. 아이러니하게도 대부분의 우수한 소프트웨어 엔지니어링 원칙은 규모에 따라 무너지기 시작합니다. 특히 애플리케이션 아키텍처 설계에 대한 고려가 많지 않은 경우에 그렇습니다. 개발자가 굴복하는 경향이 있는 가장 일반적인 실수 중 하나는 코드 문제를 혼합하는 것이며 매우 쉽습니다!
일반적으로 관심사의 분리를 깨뜨리는 것은 새로운 기능을 기존 클래스에 '덤핑'하는 것입니다. 물론 이것은 훌륭한 단기 솔루션이지만(초보자에게는 타이핑이 덜 필요함) 테스트, 유지 관리 또는 그 사이의 어딘가에 필연적으로 문제가 될 수 있습니다. 저장소에서 TopTalentData
를 반환하는 다음 컨트롤러를 고려하십시오.
@RestController public class TopTalentController { private final TopTalentRepository topTalentRepository; @RequestMapping("/toptal/get") public List<TopTalentData> getTopTalent() { return topTalentRepository.findAll() .stream() .map(this::entityToData) .collect(Collectors.toList()); } private TopTalentData entityToData(TopTalentEntity topTalentEntity) { return new TopTalentData(topTalentEntity.getName()); } }
처음에는 이 코드에 특별히 문제가 없는 것처럼 보일 수 있습니다. TopTalentEntity
인스턴스에서 검색되는 TopTalentData
목록을 제공합니다. 그러나 자세히 살펴보면 실제로 TopTalentController
가 여기에서 수행하는 몇 가지 작업이 있음을 알 수 있습니다. 즉, 요청을 특정 끝점에 매핑하고, 저장소에서 데이터를 검색하고, TopTalentRepository
에서 받은 엔터티를 다른 형식으로 변환합니다. '더 깨끗한' 솔루션은 이러한 문제를 자체 클래스로 분리하는 것입니다. 다음과 같이 보일 수 있습니다.
@RestController @RequestMapping("/toptal") @AllArgsConstructor public class TopTalentController { private final TopTalentService topTalentService; @RequestMapping("/get") public List<TopTalentData> getTopTalent() { return topTalentService.getTopTalent(); } } @AllArgsConstructor @Service public class TopTalentService { private final TopTalentRepository topTalentRepository; private final TopTalentEntityConverter topTalentEntityConverter; public List<TopTalentData> getTopTalent() { return topTalentRepository.findAll() .stream() .map(topTalentEntityConverter::toResponse) .collect(Collectors.toList()); } } @Component public class TopTalentEntityConverter { public TopTalentData toResponse(TopTalentEntity topTalentEntity) { return new TopTalentData(topTalentEntity.getName()); } }
이 계층 구조의 또 다른 이점은 클래스 이름을 조사하는 것만으로 기능이 있는 위치를 결정할 수 있다는 것입니다. 또한 테스트 중에 필요한 경우 모의 구현으로 클래스를 쉽게 대체할 수 있습니다.
일반적인 실수 #4: 불일치 및 잘못된 오류 처리
일관성의 주제는 반드시 Spring(또는 Java, 그 문제에 있어서)에만 국한되는 것은 아니지만 여전히 Spring 프로젝트에서 작업할 때 고려해야 할 중요한 측면입니다. 코딩 스타일은 논쟁의 대상이 될 수 있지만(일반적으로 팀 내 또는 전체 회사 내에서 합의의 문제임) 공통 표준을 갖는 것은 생산성 향상에 큰 도움이 됩니다. 이것은 특히 여러 사람으로 구성된 팀에 해당됩니다. 일관성을 통해 다른 클래스의 책임에 대한 긴 설명을 제공하거나 손을 잡는 데 많은 리소스를 소비하지 않고 전달이 발생할 수 있습니다.
다양한 구성 파일, 서비스 및 컨트롤러가 있는 Spring 프로젝트를 고려하십시오. 이름을 명명할 때 의미상 일관성을 유지하면 새로운 개발자가 코드를 관리할 수 있는 쉽게 검색 가능한 구조가 생성됩니다. 예를 들어 구성 클래스에 Config 접미사를 추가하고 서비스에 서비스 접미사를 추가하고 컨트롤러에 Controller 접미사를 추가합니다.
일관성이라는 주제와 밀접하게 관련된 서버 측 오류 처리는 특별히 강조할 가치가 있습니다. 잘못 작성된 API에서 예외 응답을 처리해야 하는 경우에는 예외를 적절하게 구문 분석하는 것이 힘들고 애초에 해당 예외가 발생한 이유를 파악하는 것이 훨씬 더 고통스러운 이유를 알 것입니다.
API 개발자는 이상적으로 모든 사용자 대면 끝점을 다루고 공통 오류 형식으로 변환하기를 원할 것입니다. 이것은 일반적으로 a) "500 Internal Server Error" 메시지를 반환하거나, b) 스택 추적을 사용자에게 덤프하는 것(실제로 모든 비용을 들이지 않아야 함)보다는 일반적인 오류 코드 및 설명을 갖는 것을 의미합니다. 클라이언트 측을 처리하기 어려울 뿐만 아니라 내부를 노출하기 때문입니다.
일반적인 오류 응답 형식의 예는 다음과 같습니다.
@Value public class ErrorResponse { private Integer errorCode; private String errorMessage; }
이와 유사한 것은 가장 인기 있는 API에서 흔히 접할 수 있으며 쉽고 체계적으로 문서화할 수 있기 때문에 잘 작동하는 경향이 있습니다. 예외를 이 형식으로 변환하는 것은 @ExceptionHandler
주석을 메소드에 제공하여 수행할 수 있습니다(주석의 예는 Common Mistake #6에 있음).
일반적인 실수 #5: 멀티스레딩을 부적절하게 다루기
데스크탑 또는 웹 앱에서 발생하는지 여부, Spring 또는 Spring 없음에 관계없이 멀티스레딩은 해독하기 힘든 너트가 될 수 있습니다. 프로그램의 병렬 실행으로 인해 발생하는 문제는 신경이 많이 쓰일 정도로 파악하기 어렵고 종종 디버그하기가 매우 어렵습니다. 사실 문제의 특성으로 인해 병렬 실행 문제를 다루고 있다는 사실을 알게 되면 아마도 다음과 같이 하게 될 것입니다. 근본 오류 원인을 찾을 때까지 디버거를 완전히 포기하고 코드를 "손으로" 검사해야 합니다. 불행히도 이러한 문제를 해결하기 위한 쿠키 커터 솔루션은 존재하지 않습니다. 특정 사례에 따라 상황을 평가한 다음 최선이라고 생각하는 각도에서 문제를 공격해야 합니다.
물론 이상적으로는 멀티스레딩 버그를 완전히 피하고 싶을 것입니다. 다시 말하지만, 이를 위해 모든 것을 적용할 수 있는 접근 방식은 존재하지 않지만 다음은 멀티스레딩 오류를 디버깅하고 방지하기 위한 몇 가지 실용적인 고려 사항입니다.
전역 상태 피하기
첫째, 항상 "글로벌 상태" 문제를 기억하십시오. 다중 스레드 응용 프로그램을 만드는 경우 전역적으로 수정할 수 있는 모든 항목을 면밀히 모니터링하고 가능한 경우 완전히 제거해야 합니다. 전역 변수를 수정 가능한 상태로 유지해야 하는 이유가 있는 경우 동기화를 신중하게 사용하고 애플리케이션 성능을 추적하여 새로 도입된 대기 기간으로 인해 느려지지 않았는지 확인하십시오.
가변성 피하기
이것은 함수형 프로그래밍에서 직접 나온 것이며 OOP에 맞게 조정되었으며 클래스 변경 가능성과 상태 변경을 피해야 한다고 명시되어 있습니다. 간단히 말해서, 이는 앞서 말한 setter 메소드와 모든 모델 클래스에 대한 private final 필드를 갖는 것을 의미합니다. 값이 변경되는 유일한 시간은 구성 중입니다. 이렇게 하면 경합 문제가 발생하지 않고 개체 속성에 액세스할 때 항상 올바른 값이 제공된다는 것을 확신할 수 있습니다.
중요한 데이터 기록
애플리케이션이 문제를 일으킬 수 있는 위치를 평가하고 모든 중요한 데이터를 선제적으로 기록합니다. 오류가 발생하면 어떤 요청이 수신되었는지에 대한 정보를 얻을 수 있고 응용 프로그램이 오작동하는 이유에 대해 더 잘 이해할 수 있습니다. 로깅은 추가 파일 I/O를 도입하므로 애플리케이션 성능에 심각한 영향을 미칠 수 있으므로 남용해서는 안 된다는 점에 다시 한 번 유의해야 합니다.
기존 구현 재사용
자신의 스레드를 생성해야 할 때마다(예: 다른 서비스에 대한 비동기 요청 만들기) 고유한 솔루션을 만드는 대신 기존의 안전한 구현을 재사용합니다. 이것은 대부분 스레드 생성을 위해 ExecutorServices 및 Java 8의 깔끔한 기능 스타일 CompletableFutures를 활용하는 것을 의미합니다. Spring은 또한 DeferredResult 클래스를 통한 비동기 요청 처리를 허용합니다.
일반적인 실수 #6: 주석 기반 유효성 검사를 사용하지 않음
이전의 TopTalent 서비스에 새로운 Top Talent를 추가하기 위한 엔드포인트가 필요하다고 가정해 보겠습니다. 게다가, 정말로 타당한 이유로 모든 새 이름의 길이는 정확히 10자여야 한다고 가정해 보겠습니다. 이를 수행하는 한 가지 방법은 다음과 같습니다.

@RequestMapping("/put") public void addTopTalent(@RequestBody TopTalentData topTalentData) { boolean nameNonExistentOrHasInvalidLength = Optional.ofNullable(topTalentData) .map(TopTalentData::getName) .map(name -> name.length() == 10) .orElse(true); if (nameNonExistentOrInvalidLength) { // throw some exception } topTalentService.addTopTalent(topTalentData); }
그러나 위의 (잘못된 구성에 추가하여) 실제로 '깨끗한' 솔루션이 아닙니다. 하나 이상의 유효성 유형(즉, TopTalentData
가 null이 아니고 , TopTalentData.name
이 null이 아니며 , TopTalentData.name
이 10자 길이인지)을 확인하고 데이터가 유효하지 않은 경우 예외를 throw합니다. .
이것은 Spring과 함께 Hibernate validator를 사용함으로써 훨씬 더 깔끔하게 실행될 수 있다. 먼저 유효성 검사를 지원하기 위해 addTopTalent
메서드를 리팩토링해 보겠습니다.
@RequestMapping("/put") public void addTopTalent(@Valid @NotNull @RequestBody TopTalentData topTalentData) { topTalentService.addTopTalent(topTalentData); } @ExceptionHandler @ResponseStatus(HttpStatus.BAD_REQUEST) public ErrorResponse handleInvalidTopTalentDataException(MethodArgumentNotValidException methodArgumentNotValidException) { // handle validation exception }
또한 TopTalentData
클래스에서 유효성을 검사하려는 속성을 지정해야 합니다.
public class TopTalentData { @Length(min = 10, max = 10) @NotNull private String name; }
이제 Spring은 메서드가 호출되기 전에 요청을 가로채 유효성을 검사합니다. 추가 수동 테스트를 사용할 필요가 없습니다.
동일한 결과를 얻을 수 있는 또 다른 방법은 고유한 주석을 만드는 것입니다. 비록 당신의 요구가 Hibernate의 내장 제약 세트를 초과할 때만 보통 커스텀 어노테이션을 사용할 것이지만, 이 예에서는 @Length가 존재하지 않는 척하자. 두 개의 추가 클래스를 만들어 문자열 길이를 확인하는 유효성 검사기를 만들 수 있습니다. 하나는 유효성 검사용이고 다른 하나는 속성 주석용입니다.
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) @Retention(RetentionPolicy.RUNTIME) @Documented @Constraint(validatedBy = { MyAnnotationValidator.class }) public @interface MyAnnotation { String message() default "String length does not match expected"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; int value(); } @Component public class MyAnnotationValidator implements ConstraintValidator<MyAnnotation, String> { private int expectedLength; @Override public void initialize(MyAnnotation myAnnotation) { this.expectedLength = myAnnotation.value(); } @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { return s == null || s.length() == this.expectedLength; } }
이러한 경우 관심 분리에 대한 모범 사례에서는 속성이 null( isValid
메서드 내에서 s == null
)인 경우 유효한 것으로 표시하고, 이것이 추가 요구 사항인 경우 @NotNull
주석을 사용하도록 요구합니다. 재산:
public class TopTalentData { @MyAnnotation(value = 10) @NotNull private String name; }
일반적인 실수 #7: (여전히) XML 기반 구성 사용
이전 버전의 Spring에서는 XML이 필수였지만 오늘날 대부분의 구성은 Java 코드/주석을 통해서만 수행할 수 있습니다. XML 구성은 추가적이고 불필요한 상용구 코드로 가장합니다.
이 기사(및 함께 제공되는 GitHub 리포지토리)는 Spring을 구성하기 위해 주석을 사용하고 Spring은 다음과 같이 @SpringBootApplication
복합 주석으로 루트 패키지에 주석이 달렸기 때문에 연결해야 하는 빈을 알고 있습니다.
@SpringBootApplication public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
복합 주석(Spring 문서에서 이에 대해 자세히 알아볼 수 있습니다. 단순히 Spring에서 빈을 검색하기 위해 스캔해야 하는 패키지에 대한 힌트를 제공합니다. 우리의 구체적인 경우에는 최상위(co.kukurin) 패키지 아래에 다음이 사용됨을 의미합니다. 배선용:
-
@Component
(TopTalentConverter
,MyAnnotationValidator
) -
@RestController
(TopTalentController
) -
@Repository
(TopTalentRepository
) -
@Service
(TopTalentService
) 클래스
@Configuration
주석이 추가된 클래스가 있는 경우 Java 기반 구성도 확인됩니다.
일반적인 실수 #8: 프로필에 대해 잊어버리기
서버 개발에서 자주 발생하는 문제는 일반적으로 프로덕션 및 개발 구성과 같은 다양한 구성 유형을 구별하는 것입니다. 테스트에서 애플리케이션 배포로 전환할 때마다 다양한 구성 항목을 수동으로 교체하는 대신 프로필을 사용하는 것이 더 효율적인 방법입니다.
프로덕션 환경에서 MySQL 데이터베이스와 함께 로컬 개발을 위해 인메모리 데이터베이스를 사용하는 경우를 고려하십시오. 이것은 본질적으로 두 가지 각각에 액세스하기 위해 다른 URL과 (잘하면) 다른 자격 증명을 사용하게 될 것임을 의미합니다. 두 개의 다른 구성 파일이 어떻게 수행되는지 봅시다.
application.yaml 파일
# set default profile to 'dev' spring.profiles.active: dev # production database details spring.datasource.url: 'jdbc:mysql://localhost:3306/toptal' spring.datasource.username: root spring.datasource.password:
application-dev.yaml 파일
spring.datasource.url: 'jdbc:h2:mem:' spring.datasource.platform: h2
아마도 코드를 수정하는 동안 프로덕션 데이터베이스에서 실수로 작업을 수행하고 싶지 않을 것이므로 기본 프로필을 dev로 설정하는 것이 좋습니다. 그런 다음 서버에서 -Dspring.profiles.active=prod
매개변수를 JVM에 제공하여 구성 프로필을 수동으로 재정의할 수 있습니다. 또는 OS의 환경 변수를 원하는 기본 프로필로 설정할 수도 있습니다.
흔한 실수 #9: 의존성 주입 수용 실패
Spring과 함께 종속성 주입을 적절하게 사용하면 원하는 모든 구성 클래스를 스캔하여 모든 객체를 함께 연결할 수 있습니다. 이것은 관계를 분리하는 데 유용하고 테스트를 훨씬 쉽게 만듭니다. 다음과 같이 하여 긴밀한 결합 클래스 대신:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController() { this.topTalentService = new TopTalentService(); } }
우리는 Spring이 우리를 위해 배선을 하도록 허용합니다:
public class TopTalentController { private final TopTalentService topTalentService; public TopTalentController(TopTalentService topTalentService) { this.topTalentService = topTalentService; } }
Misko Hevery의 Google 토크는 종속성 주입의 '이유'에 대해 자세히 설명하므로 대신 실제로 어떻게 사용되는지 봅시다. 관심사 분리 섹션(Common Mistakes #3)에서 서비스 및 컨트롤러 클래스를 만들었습니다. TopTalentService
가 올바르게 작동한다는 가정 하에 컨트롤러를 테스트한다고 가정해 보겠습니다. 별도의 구성 클래스를 제공하여 실제 서비스 구현 대신 모의 객체를 삽입할 수 있습니다.
@Configuration public class SampleUnitTestConfig { @Bean public TopTalentService topTalentService() { TopTalentService topTalentService = Mockito.mock(TopTalentService.class); Mockito.when(topTalentService.getTopTalent()).thenReturn( Stream.of("Mary", "Joel").map(TopTalentData::new).collect(Collectors.toList())); return topTalentService; } }
그런 다음 Spring에 SampleUnitTestConfig
를 구성 공급자로 사용하도록 지시하여 모의 객체를 주입할 수 있습니다.
@ContextConfiguration(classes = { SampleUnitTestConfig.class })
그러면 컨텍스트 구성을 사용하여 사용자 정의 빈을 단위 테스트에 주입할 수 있습니다.
일반적인 실수 #10: 테스트 부족 또는 부적절한 테스트
단위 테스트에 대한 아이디어가 우리와 함께한 지 오래지만 많은 개발자가 이 작업을 수행하는 것을 "잊거나"(특히 필요하지 않은 경우 ) 단순히 나중에 생각하는 것으로 추가하는 것 같습니다. 테스트는 코드의 정확성을 검증할 뿐만 아니라 다양한 상황에서 애플리케이션이 어떻게 작동해야 하는지에 대한 문서 역할도 해야 하기 때문에 이것은 분명히 바람직하지 않습니다.
웹 서비스를 테스트할 때 HTTP를 통한 통신은 일반적으로 Spring의 DispatcherServlet
을 호출 하고 실제 HttpServletRequest
가 수신될 때 어떤 일이 발생하는지 확인해야 하기 때문에 '순수' 단위 테스트를 거의 수행하지 않습니다. , 등). MockMVC를 기반으로 하는 REST 서비스의 손쉬운 테스트를 위한 Java DSL인 REST Assured는 매우 우아한 솔루션을 제공하는 것으로 입증되었습니다. 종속성 주입이 있는 다음 코드 조각을 고려하세요.
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = { Application.class, SampleUnitTestConfig.class }) public class RestAssuredTestDemonstration { @Autowired private TopTalentController topTalentController; @Test public void shouldGetMaryAndJoel() throws Exception { // given MockMvcRequestSpecification givenRestAssuredSpecification = RestAssuredMockMvc.given() .standaloneSetup(topTalentController); // when MockMvcResponse response = givenRestAssuredSpecification.when().get("/toptal/get"); // then response.then().statusCode(200); response.then().body("name", hasItems("Mary", "Joel")); } }
SampleUnitTestConfig
는 TopTalentService의 모의 구현을 TopTalentService
에 TopTalentController
하는 반면, 다른 모든 클래스는 Application 클래스의 패키지를 기반으로 하는 스캐닝 패키지에서 추론된 표준 구성을 사용하여 연결됩니다. RestAssuredMockMvc
는 단순히 경량 환경을 설정하고 /toptal/get
엔드포인트에 GET
요청을 보내는 데 사용됩니다.
스프링 마스터 되기
Spring은 시작하기 쉽지만 완전히 숙달하려면 약간의 헌신과 시간이 필요한 강력한 프레임워크입니다. 시간을 내어 프레임워크에 익숙해지면 장기적으로 생산성이 확실히 향상되고 궁극적으로 더 깨끗한 코드를 작성하고 더 나은 개발자가 되는 데 도움이 됩니다.
추가 리소스를 찾고 있다면 Spring In Action이 많은 핵심 Spring 주제를 다루는 좋은 실습 책입니다.