묻고 답해요
141만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
테스트 코드를 위한 @Builder, 생성자
안녕하세요api 에서 request 를 받는 경우 getter 만 열어두고 사용하는 경우가 있는데요,이런 경우엔 request dto에 테스트 코드를 위한 생성자나 builder를 추가해주는게 맞을까요?테스트 코드를 짜기 위해 실제 코드를 수정하는 부분이 찝찝해 질문드립니다
-
해결됨
김영한 강사님 강의에 대한 오류 질문입니다.
김영한 강사님의 스프링 핵심원리 기본편을 수강하다가 나온 오류입니다.모든 테스트를 실행했는데 이러한 오류가 나왔습니다. 해결책을 알려주시면 감사하겠습니다. java.lang.IllegalStateException: Failed to load ApplicationContext for [MergedContextConfiguration@63bde6c2 testClass = hello.core.CoreApplicationTests, locations = [], classes = [hello.core.CoreApplication], contextInitializerClasses = [], activeProfiles = [], propertySourceDescriptors = [], propertySourceProperties = ["org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true"], contextCustomizers = [org.springframework.boot.test.autoconfigure.actuate.observability.ObservabilityContextCustomizerFactory$DisableObservabilityContextCustomizer@1f, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizer@58670130, org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@59d2103b, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@18518ccf, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@6722db6e, org.springframework.boot.test.context.SpringBootTestAnnotation@e348e9fb], contextLoader = org.springframework.boot.test.context.SpringBootContextLoader, parent = null] at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:180) at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:130) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:142) at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:98) at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:260) at org.springframework.test.context.junit.jupiter.SpringExtension.postProcessTestInstance(SpringExtension.java:163) at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625) at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) at java.base/java.util.stream.StreamSpliterators$WrappingSpliterator.forEachRemaining(StreamSpliterators.java:310) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:735) at java.base/java.util.stream.Streams$ConcatSpliterator.forEachRemaining(Streams.java:734) at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762) at java.base/java.util.Optional.orElseGet(Optional.java:364) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberServiceImpl' defined in file [C:\study\core\out\production\classes\hello\core\member\MemberServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memberRepository at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:798) at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:237) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1355) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1192) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:562) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:522) at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:325) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:323) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:975) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:959) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:624) at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:754) at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:456) at org.springframework.boot.SpringApplication.run(SpringApplication.java:334) at org.springframework.boot.test.context.SpringBootContextLoader.lambda$loadContext$3(SpringBootContextLoader.java:137) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:58) at org.springframework.util.function.ThrowingSupplier.get(ThrowingSupplier.java:46) at org.springframework.boot.SpringApplication.withHook(SpringApplication.java:1454) at org.springframework.boot.test.context.SpringBootContextLoader$ContextLoaderHook.run(SpringBootContextLoader.java:553) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:137) at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:108) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:225) at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:152) ... 17 moreCaused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'hello.core.member.MemberRepository' available: expected single matching bean but found 2: memoryMemberRepository,memberRepository at org.springframework.beans.factory.config.DependencyDescriptor.resolveNotUnique(DependencyDescriptor.java:218) at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1420) at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1353) at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:907) at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:785) ... 41 more
-
미해결
스프링부트 테스트에서 @AuthenticationPrincipal UserDetails userDetails 테스트
컨트롤러 테스트에서 @AuthenticationPrincipal UserDetails userDetails에 해당하는 부분을 테스트하려고 하는데 계속 실패해서 질문드립니다 ㅠㅠ // 회원 탈퇴 @DeleteMapping("/{memberId}") @Tag(name = "member") @Operation(summary = "삭제 API", description = "유저를 삭제하는 API입니다.") @PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") public String remove(@PathVariable Long memberId, @AuthenticationPrincipal UserDetails userDetails) { try { String email = userDetails.getUsername(); log.info("email : " + email); String remove = memberService.removeUser(memberId, email); return remove; } catch (Exception e) { return "회원탈퇴 실패했습니다. :" + e.getMessage(); } }이런식으로 프론트가 헤더에 accessToken을 보내주면 검증을 한 후 @AuthenticationPrincipal UserDetails userDetails이거로 정보를 가져와서 권한과 해당 유저인지 체크 후 처리하는 로직을 구성하고 있는데 이거를 테스트할 때 막혔습니다.일단 구글에서 검색해서 나온 방법들을 다 사용해도 실패가 뜨네요.↓구글에서 나온 방법 적용@Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithAuthUserSecurityContextFactory.class) public @interface WithAuthUser { String user() default "test@test.com"; String role() default "USER"; }public class WithAuthUserSecurityContextFactory implements WithSecurityContextFactory<WithAuthUser> { @Override public SecurityContext createSecurityContext(WithAuthUser annotation) { String email = annotation.user(); String role = annotation.role(); MemberEntity member = MemberEntity.builder() .memberId(1L) .email(email) .memberPw("dudtjq8990!") .memberName("테스터") .memberRole(Role.valueOf(role)) .nickName("테스터") .memberPoint(0) .provider(null) .providerId(null) .address(AddressEntity.builder() .memberAddr("서울시 강남구") .memberZipCode("103-332") .memberAddrDetail("102") .build()) .build(); UserDetails userDetails = new PrincipalDetails(member); Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(authentication); return context; } } @Test @WithAuthUser void remove() throws Exception { Long id = 1L; String email = "test@test.com"; mockMvc.perform(delete("/api/v1/users/{memberId}", id) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); verify(memberService).removeUser(id, email); } org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.security.core.userdetails.UserDetails 이런 오류가 발생합니다. 찾아보니까 UserDetails를 구현한 클래스 PrincipalDetails에 생성자가 없어서 나오는 오류라고 하는데 문제는 해당 클래스에 기본 생성자가 있다는 것입니다. 생성자가 있는데 계속 없다고 에러가 발생합니다. @ㅇNoArgsConstructorㅇ
-
미해결스프링 핵심 원리 - 기본편
왜 순수한 자바로 테스트 해야 하나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)네2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)네3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)네[질문 내용]1. 제목과 같은 내용입니다. 강의 어느 편인가 해당 내용에 대해서 짧게 답변 해주신 부분을 어렴풋이 본거 같은데 잊어서 질문 드립니다. 해당 질문에 대한 답변 또는 관련 영상을 혹시 아신다면 감사 드릴거 같습니다.2. 해당 질문에 대한 원인은 다음과 같습니다. 순수한 자바 코드가 스프링 프레임워크를 포함한 것보다 상대적으로 작은 범위여서 일단 공통 부분인 자바 파트에서 테스트를 하고 그 다음 스프링으로 가는 것이 맞겠다는게 처음 생각이었습니다. 근데 문득 이게 맞나 ? 명확한 근거가 아닌 저의 추측에 기반한 근거였기 때문에 1번의 설명과 같이 모호해서 질문을 드립니다.개발자인데 아직도 문서를 두서 없이 작성합니다.해당 부분에 있어 양해를 구합니다.읽어주셔서 감사합니다.
-
미해결재고시스템으로 알아보는 동시성이슈 해결방법
비관적 락 적용을 해도 동시성 테스트 시 실패합니다...
StockRepositorypublic interface StockRepository extends JpaRepository<Stock, Long> { @Lock(value = LockModeType.PESSIMISTIC_WRITE) @Query("select s from Stock s where s.id = :id") Stock findByIdWithPessimisticLock(@Param("id") Long id); }StockService@Service @RequiredArgsConstructor public class StockService { private final StockRepository stockRepository; @Transactional public Long decrease(Long id, Long quantity) { Stock stock = stockRepository.findByIdWithPessimisticLock(id); stock.decrease(quantity); stockRepository.saveAndFlush(stock); return stock.getQuantity(); } }StockServiceTest@SpringBootTest class PessimisticLockStockServiceTest { @Autowired private StockService service; @Autowired private StockRepository stockRepository; @BeforeEach public void before() { stockRepository.saveAndFlush(new Stock(1L, 100L)); } @AfterEach public void after() { stockRepository.deleteAll(); } @Test @DisplayName("비관적 락을 사용해 재고 감소 동시성 요청이 완료된다.") void decrease() throws InterruptedException { // given int threadCnt = 100; ExecutorService executorService = Executors.newFixedThreadPool(32); CountDownLatch latch = new CountDownLatch(threadCnt); // when for (int i = 0; i < threadCnt; i++) { executorService.submit(() -> { try { service.decrease(1L, 1L); } finally { latch.countDown(); } }); } latch.await(); // then Stock stock = stockRepository.findById(1L).orElseThrow(); assertThat(stock.getQuantity()).isZero(); } }해당 테스트를 돌리면 실패하고 순차적으로 재고가 감소되지 않고 수정 손실이 발생합니다. 아무리 찾아봐도 코드는 제대로 짠 것 같은데 무엇이 잘못 되었을까요??
-
해결됨
애드몹 테스트 광고가 안떠요 ㅠ
이런 로그캣이 뜨는데 이유가 뭘까요 ㅠㅠ 이건 모듈 그래들 파일입니다.plugins { id("com.android.application") } android { namespace = "com.example.admobtest" compileSdk = 33 defaultConfig { applicationId = "com.example.admobtest" minSdk = 20 targetSdk = 33 versionCode = 1 versionName = "1.0" testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isMinifyEnabled = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } compileOptions { sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } } dependencies { implementation ("com.google.android.gms:play-services-ads:21.1.0") implementation("androidx.appcompat:appcompat:1.6.1") implementation("com.google.android.material:material:1.9.0") implementation("androidx.constraintlayout:constraintlayout:2.1.4") testImplementation("junit:junit:4.13.2") androidTestImplementation("androidx.test.ext:junit:1.1.5") androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1") } 이건 메인 액티비티.자바 파일입니다.package com.example.admobtest; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.AdView; import com.google.android.gms.ads.MobileAds; import com.google.android.gms.ads.initialization.InitializationStatus; import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; public class MainActivity extends AppCompatActivity { private AdView mAdView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); MobileAds.initialize(this, new OnInitializationCompleteListener() { @Override public void onInitializationComplete(InitializationStatus initializationStatus) { } }); mAdView = findViewById(R.id.adView); AdRequest adRequest = new AdRequest.Builder().build(); mAdView.loadAd(adRequest); } } 이건 액티비티 메인.xml 파일입니다.<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <com.google.android.gms.ads.AdView xmlns:ads="http://schemas.android.com/apk/res-auto" android:id="@+id/adView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true" ads:adSize="BANNER" ads:adUnitId="ca-app-pub-3940256099942544/6300978111"> </com.google.android.gms.ads.AdView> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Hello World!" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> 이건 마니페스트 파일입니다.<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="com.google.android.gms.permission.AD_ID"/> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.AdmobTest" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="ca-app-pub-3940256099942544~3347511713"/> </application> </manifest> 계속봐도 뭐가 문제인지 잘 모르겠습니다. ㅠㅠ혹시 원인이랑 수정해야하는 부분을 알 수 있을까요?
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
테스트 코드 작성에 대한 질문
테스트 코드를 작성할 때 테스트하려는 메서드를 제외한 나머지 메서드들은 전부 정상적으로 동작한다고 가정하고 해야하는 건가요??테스트코드를 작성하다보니 헷갈려서 질문 드립니다.. 예를 들면 findById() 메서드를 테스트할때save() 메서드는 정상 동작한다고 가정하고 하는건가요?
-
미해결
Unit Testing 을 위해서 Repository를 Mock했는데 먹지를 않습니다.
안녕하세요.Unit Testing 을 처음 해보는데 일단 Service의 로직을 먼저 테스트하기 위해 Repository를 Mock해서 Service 내에 @InsertMocks 어노테이션을 걸어서 when 조건을 삽입했습니다.이후 Service 내에서 findById(1L)을 실행하면 when문에서 걸어준대로 User 객체를 반환해야 한다고 생각했으나, 계속 Optional이 비어있다고 나오네요.그래서 Service로 들어간것이 아니라 직접 Test 내에서 Repository를 불러본 결과 Mock가 문제없이 잘 되고 있었습니다. 제가 Configuration 한 것에 문제가 있는지 고견 부탁드립니다.UserServiceTest import com.politicia.coreservice.domain.User; import com.politicia.coreservice.dto.request.UserRequestDto; import com.politicia.coreservice.dto.response.UserResponseDto; import com.politicia.coreservice.repository.UserRepository; import org.junit.jupiter.api.Assertions; 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.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import java.util.ArrayList; import java.util.List; import java.util.Optional; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class UserServiceTest { @InjectMocks UserServiceImpl userService; @Mock private UserRepository userRepository; @BeforeEach public void setUp() { MockitoAnnotations.initMocks(this); } @Test void testSignUp() { //given UserRequestDto newUser = UserRequestDto.builder() .name("newUser") .profilePic("https://profile.pic") .nationality("korea") .build(); User expectedUser = User.builder() .id(1L) .name("newUser") .nationality("korea") .profilePic("https://profile.pic") .build(); UserResponseDto expectedUserDto = UserResponseDto.builder() .id(1L) .name("newUser") .nationality("korea") .profilePic("https://profile.pic") .createdAt(expectedUser.getCreatedAt()) .updatedAt(expectedUser.getUpdatedAt()) .build(); when(userRepository.save(any(User.class))).thenReturn(expectedUser); //when UserResponseDto actualUser = userService.createUser(newUser); // Verify assertEquals(expectedUserDto, actualUser); } @Test void testGetUser() { //given User user = User.builder() .id(1L) .name("user") .nationality("korea") .profilePic("profilePic") .build(); List<User> userList = new ArrayList<>(); userList.add(user); when(userRepository.findById(any(Long.class))).thenReturn(Optional.of(user)); UserResponseDto expectedUserDto = UserResponseDto.builder() .id(1L) .name("user") .nationality("korea") .profilePic("profilePic") .createdAt(user.getCreatedAt()) .updatedAt(user.getUpdatedAt()) .build(); //when UserResponseDto actualUserDto = userService.getUser(1L); //then Assertions.assertEquals(actualUserDto, expectedUserDto); } } UserServiceImplpackage com.politicia.coreservice.service; import com.politicia.coreservice.domain.User; import com.politicia.coreservice.dto.request.UserRequestDto; import com.politicia.coreservice.dto.response.UserResponseDto; import com.politicia.coreservice.repository.UserRepository; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service @RequiredArgsConstructor public class UserServiceImpl implements UserService { private final UserRepository userRepository; @Override public UserResponseDto createUser(UserRequestDto userRequestDto) { User user = userRequestDto.toEntity(); User newUser = userRepository.save(user); return UserResponseDto.builder() .id(newUser.getId()) .name(newUser.getName()) .nationality(newUser.getNationality()) .profilePic(newUser.getProfilePic()) .createdAt(newUser.getCreatedAt()) .updatedAt(newUser.getUpdatedAt()) .build(); } @Override public UserResponseDto getUser(Long userId) { User foundUser = userRepository.findById(userId).get(); return UserResponseDto.builder() .id(foundUser.getId()) .name(foundUser.getName()) .nationality(foundUser.getNationality()) .profilePic(foundUser.getProfilePic()) .createdAt(foundUser.getCreatedAt()) .updatedAt(foundUser.getUpdatedAt()) .build(); } }에러문구
-
해결됨스프링 DB 2편 - 데이터 접근 활용 기술
임베디드 모드 테스트 시 sql 스크립트
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요.영한 님의 강의를 수강한 뒤 간단한 게시판 프로젝트를 작업해보고 있습니다.말씀해주신 임베디드 모드를 테스트에 적용하기 위해 다음과 같이 설정해봤습니다.test의 resources/application.properties에는 단순히 로그와 관련된 것만 입력해두었습니다.logging.level.org.springframework.jdbc=debug # Can check SQL which Hibernate run and create logging.level.org.hibernate.SQL=DEBUG # Can check parameters which binding in SQL logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE멤버 엔티티입니다.package com.devholic22.board.entity; import jakarta.persistence.*; import lombok.Data; @Data @Entity public class Member { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(name = "user_name", length = 10) private String name; @Column(length = 10) private String password; public Member() { } public Member(String name, String password) { this.name = name; this.password = password; } } 멤버 리포지토리입니다.package com.devholic22.board.repository; import com.devholic22.board.entity.Member; import org.springframework.data.jpa.repository.JpaRepository; public interface MemberRepository extends JpaRepository<Member, Long> { } 테스트 코드입니다.package com.devholic22.board.repository; import com.devholic22.board.entity.Member; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @Slf4j @SpringBootTest public class MemberRepositoryTest { @Autowired MemberRepository repository; @Test void save() { Member member = new Member("testerA", "1234"); Member savedMember = repository.save(member); log.info(savedMember.toString()); } } 그런데 강의에서 이야기하셨던 SQL 스크립트를 만들어두지 않았는데도, 테스트가 제대로 실행되었습니다.원래 예상했던 결과는 Table "MEMBER" not found와 같은 부분인데, 왜 이런 에러가 발생하지 않았는지 궁금합니다.테스트 코드 결과입니다.2022-12-11T13:15:08.008+09:00 INFO 65418 --- [ main] c.d.b.repository.MemberRepositoryTest : Started MemberRepositoryTest in 7.134 seconds (process running for 9.374) 2022-12-11T13:15:08.427+09:00 DEBUG 65418 --- [ main] org.hibernate.SQL : insert into member (id, user_name, password) values (default, ?, ?) 2022-12-11T13:15:08.501+09:00 INFO 65418 --- [ main] c.d.b.repository.MemberRepositoryTest : Member(id=1, name=testerA, password=1234) 2022-12-11T13:15:08.547+09:00 INFO 65418 --- [ionShutdownHook] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default' 2022-12-11T13:15:08.549+09:00 INFO 65418 --- [ionShutdownHook] .SchemaDropperImpl$DelayedDropActionImpl : HHH000477: Starting delayed evictData of schema as part of SessionFactory shut-down' 2022-12-11T13:15:08.550+09:00 DEBUG 65418 --- [ionShutdownHook] org.hibernate.SQL : drop table if exists member cascade 2022-12-11T13:15:08.555+09:00 INFO 65418 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown initiated... 2022-12-11T13:15:08.560+09:00 INFO 65418 --- [ionShutdownHook] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Shutdown completed.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
테스트 에러 질문드립니다.
안녕하세요 테스트를 진행하던 중 오류가 발생하여 질문드립니다. 테스트 케이스를 클래스 레벨로 진행하면 문제 없이 잘 실행이 되나한글명의 메서드 상품주문() 레벨에서 테스트를 진행시 해당 에러가 발생합니다.java.lang.Exception: No tests found matching Method �긽�뭹二쇰Ц(jpabook.jpashop.service.OrderServiceTest) from org.junit.internal.requests.ClassRequest@6c2ed0cd 해당 메서드 명을 영어로 바꿔보니 메서드 레벨에서도 진행이 잘 되더라구요... 인프런에 답변들을 보고encoding 형식을 UTF-8로 설정하였으며idea64.exe.vmoptions엔 해당 코드를 추가하였고-Dfile.encoding=UTF-8테스트 진행을 gradle이 아닌 인텔리제이로 설정까지 하였으나 해당 오류를 해결하지 못하였습니다.혼자선 도저히 해결을 못하겠어 질문남깁니다...build.gradle 과 test 코드 첨부합니다..plugins { id 'java' id 'org.springframework.boot' version '2.7.5' id 'io.spring.dependency-management' version '1.0.15.RELEASE' } group = 'jpabook' version = '0.0.1-SNAPSHOT' sourceCompatibility = '11' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-devtools' implementation 'com.github.gavlyukovskiy:p6spy-spring-boot-starter:1.5.6' compileOnly 'org.projectlombok:lombok' runtimeOnly 'com.h2database:h2' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation("org.junit.vintage:junit-vintage-engine") { exclude group: "org.hamcrest", module: "hamcrest-core" } } test { useJUnitPlatform() } tasks.named('test') { useJUnitPlatform() } package jpabook.jpashop.service; import jpabook.jpashop.Repository.MemberRepository; import jpabook.jpashop.domain.Member; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.transaction.annotation.Transactional; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest @Transactional public class MemberServiceTest { @Autowired MemberService memberService; @Autowired MemberRepository memberRepository; @Test public void 회원가입() throws Exception { //Given Member member = new Member(); member.setName("kim"); //When Long saveId = memberService.join(member); //Then assertEquals(member, memberRepository.findOne(saveId)); } @Test(expected = IllegalStateException.class) public void 중복_회원_예외() throws Exception { //Given Member member1 = new Member(); member1.setName("kim"); Member member2 = new Member(); member2.setName("kim"); //When memberService.join(member1); memberService.join(member2); //예외가 발생해야 한다. //Then fail("예외가 발생해야 한다."); } }
-
미해결스프링 핵심 원리 - 고급편
로그 검증과 관련되어 질문드립니다.
안녕하세요! 강의를 듣다가 로그 검증이 하고 싶어 진행하다 궁금증이 생겨 질문글을 올렸습니다.☺️ 1. 생성한로그를 테스트하기 위해서 ListAppender에 로그들을 담아서 테스트를 진행하게 됐는데, 해당 방식으로 테스트를 진행하는 방법말고도 다른 방법도 있나요? 2. 실제 비즈니스 로직에서 해당 로그 출력 검증을 단위 테스트할 때 진행하게 되나요? 3. 실무에서는 로그를 검증하기 위해 어떤 방식을 사용하는지 궁금합니다.
-
미해결
프로드와 스테이징
안녕하세요 콘텐츠 디자이너입니다. 이번에 회사에서 신규 사업으로 앱 개발을 하는데 제가 테스트랑 디자인에 참여하게 되었어요. 근데 배포된 앱과 테스트용 앱을 각각 프로드, 스테이징이라고 부르더라고요. 프로드와 스테이징의 어원은 뭐며 이런 용어들은 어디서 공부할 수 있을까요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
테스트에서의 bindingResult 오작동
안녕하세요. 스프링 Junit 테스트로 검증 부분을 테스트 하던 중 의도대로 되지 않는 부분이 있어서 질문드립니다. 먼저 테스트 하려는 컨트롤러는 JSON 데이터를 파라미터로 받아서 검증을 하고 (@Valid @RequestBody) 검증이 실패하면(bindingResult.hasErrors가 true일 때) 예외를 발생시키는데, 해당 예외는 컨트롤러 어드바이스로 받아 http 400코드를 응답 하게끔 설계를 하였습니다. (포스트맨으로 검증에 실패하는 데이터를 보냈을 때 400으로 응답되는 것을 확인하였습니다.) 그런데 테스트 코드에선 검증에 통과못하는 데이터를 넣어 mockMvc.perform으로 테스트 해보니 기대와는 다르게 http 200코드가 찍히면서 검증이 통과되는 결과가 나왔습니다. (andExpect에서 getResolvedException()이 null로 찍히는 것을 보니 bindingResult.hasErrors가 false가 되는 것 같습니다) 컨트롤러 어드바이스가 문제인가 싶어서 다른 예외를 발생시켜 테스트 해보았는데, 다른 예외는 잘 처리되더라구요. 혹시 이러한 검증 로직을 mockMvc로 테스트 하는 방법이 따로 있는 것 일까요? 스프링은 5.x.x 버전이며 junit은 4.12 버전을 사용 중 입니다.
-
미해결스프링 핵심 원리 - 기본편
build.gradle 질문입니다.
안녕하세요! 테스트 하려고 build.gradle에 JUnit이 어떻게 주입되어 있나 확인해보았는데 저는 이렇게 되어있습니다. 강의에서는 test { useJUnitPlatform() }으로 되어있는데 저는 왜 이렇게 설정이 되어있는 것인가요? userJUnitPlatform에 점선밑줄이 그어져 마우스를 대보니 "메서드 호출 userJUnitPlatform의 후보를 찾을 수 없습니다" 라고 뜹니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
테스트케이스 작성시 오류가 나는데 원인을 모르겠습니다..ㅠㅠ
11강 회원 레포지토리 테스트케이스를 작성하는 과정에서 에러가 나옵니다.. save와 findById, findByName부분에서 타입이 다르다고 하는데 무슨의미인지는 모르겠습니다.. 코드와 오류가 난 부분을 캡쳐해서 올리겠습니다.. 추가로 vscode를 이용하고 있는데, 혹시 이것이 원인은 아니겠지요..? 스프링이 처음이라 정말 막막한데 항상 많은 도움주셔서 감사합니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
강의자료에 있는 내용 중에 궁금한 것이 있어 질문드립니다.
안녕하세요. 이번 강의에서는 Servlet 종속성을 제거하기 위해 'ModelView' 객체를 만들고, 이를 적극 활용하는 컨트롤러를 만드는 것에 대해 다루었는데요. 강의 자료에 다음과 같은 내용이 있었습니다. (빨간색으로 밑줄 그은 내용) 여기서 말하는 "테스트하기 쉽다" 라는 말은 정확히 어떤 의미인가요? 무언가에 종속적이면 테스트 코드를 작성하기 어렵다는 뜻으로 받아들여도 되는걸까요? 조금 더 구체적으로 설명해주시면 정말 감사하겠습니다!
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
테스트 실행 시 데이터베이스 전체 조회
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 아니오[질문 내용]MemberServiceTest를 실행하면 사진처럼 데이터베이스에 select문을 날립니다. 저런 쿼리를 날리는 코드는 작성하지 않았는데... 이렇게 나오는게 맞나요..? 아니라면 해결방안이 궁금합니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Mockito 를 사용하여 테스트할 때, 테스트 요구사항의 반영 질문
이번 강의의 1분 30초 쯤, 현재 작성하는 테스트 방법이 그다지 좋은 방법은 아니다라는 말을 들었습니다. 그래서 좋은 테스트 방법은 무엇인지 찾아보게 되었고 돌아돌아 Mockito 같은 테스트 프레임워크를 알게되었습니다. 좋은건 일단 맛은 봐야하는 성격이라, 강의를 듣다말고 Mockito 를 사용하여 단위 테스트 하는 방법 알아보는 길로 한참 새버렸습니다 ㅎㅎㅎ Mockito 를 사용해서 OrderService 의 주문 성공에 대한 테스트 코드를 작성해보았습니다. 근데 영한 선생님이 강의에서 작성할 때의 assertEquals 이나 그런 요구사항들에 대해선 테스트를 못해서 제가 테스트 코드 작성을 잘못한건가 하는 생각이 들었습니다. 코드는 다음과 같이 간단하게 작성했습니다. @ExtendWith(MockitoExtension.class) class OrderServiceTest { @Mock MemberRepository memberRepository; @Mock ItemRepository itemRepository; @Mock OrderRepository orderRepository; @InjectMocks OrderService orderService; @Test @DisplayName("주문 성공") void order() { Member member = new Member( 1L, "irostub", new Address("seoul", "street", "10000"), new ArrayList<>()); Item item = new Book( 1L, "itemName", 15000, 2021, new ArrayList<>(), "5pg", "isbn5100"); //given given(memberRepository.findOne(anyLong())) .willReturn(member); given(itemRepository.findOne(anyLong())) .willReturn(item); //when orderService.order(1L, 1L, 100); //then ArgumentCaptor<Order> captor = ArgumentCaptor.forClass(Order.class); then(orderRepository).should(times(1)).save(captor.capture()); } } 코드는 위와 같습니다. 뭔가 많이 허전합니다. 강의에서 처럼 assertEqual()에 인자로 넣을 객체를 받아올 방법이 없어서 , orderRepository.save(...) 는 void를 반환하고 orderService.order(...) 은 Long 을 반환하지만 영속성 컨텍스트도 없으므로 null 을 반환합니다. 그래서 결국 테스트 한 것이라곤, Mock 을 통해 적당한 맴버, 상품을 정해놓고 orderService.order(...) 메서드를 실행중에 orderRepository.save(...) 을 잘 호출했는가? 뿐입니다. 이렇게 하는게 맞는걸까요..? (테스트에 대한 강의가 아님에도 이런 질문을 하는게 죄송스러울 따름입니다..ㅠㅠ 근데 어디다 물어볼 곳도 없어서 심란한 마음에 글을 씁니다)
-
미해결스프링 핵심 원리 - 기본편
테스트 관련 질문드립니다.
1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]테스트에서 beforeEach를 쓰신 이유를 알 수 있을까요? 어차피 싱글톤스럽게 써도 될 것 같은데 beforeAll을 안쓰신 이유가 궁금해서 질문드립니다.
-
미해결스프링 핵심 원리 - 기본편
테스트에 대한 질문
안녕하세요 본 강의의 핵심 내용은 아니지만 테스트 관련해서 궁금한 점이 있어 여쭤봅니다. 1. 협업 현장에서 하나의 테스트 (@Test 1개) 에 대해서 다양한 데이터로 돌아가면서 테스트를 진행하나요? 2. 만약 그렇다면 하나의 테스트에 적용할 다수의 데이터에 대해서 디자인 패턴이 있을 것 같은데 어떤 방식으로 짜는지 궁금합니다. 2번에 대해서 구글링도 해보고 고민을 해봤는데 뭔가 정석? 이 아닌것 같아 질문 드립니다. 아래는 예제 코드입니다. // test 클래스 일부 @Test void join() { //given Member member = MemberTestUtil.getMemberSample("sample1"); //when, then 생략 } // MemberTestUtil 클래스 public class MemberTestUtil { public static Member getMemberSample(String descriptor) { Member member = new Member(); // Member는 @builder 포함 switch (descriptor) { case "sample1": member.builder().id(1L).name("memberA").grade(Grade.VIP); break; case "sample2": member.builder().id(2L).name("memberB").grade(Grade.VIP); break; // 생략 } return member; } }