묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
테스트 코드
안녕하세요 좋은 강의 잘 들었습니다~!강의를 모두 듣고 제공해주신 프로젝트를 쭉 확인하고 궁금한 점이 생겨서 문의를 남겨봅니다저는 실무에서 도메인 모델과 엔티티 모델을 구분하지 않고도메인 모델에 JPA관련 어노테이션을 모두 허용한 상태로 개발해왔습니다물론 구분해서 개발해본적도 있었지만컬럼 변경 등 다양한 변경사항에 대응할 때마다 도메인 모델과 엔티티모델을 둘 다 확인하고 변경해야하는 번거러움?이 생겼던거 같아서 클래스가 좀 지저분해지더라도 도메인 모델 하나로 개발하고 테스트 코드를 작성해왔었습니다이번 강의에서 사용된 프로젝트의 경우모듈과 패키지가 나눠져있어서 도메인 모델과 엔티티 모델이 분리되어있는듯 보이지만 제가 사용했던 구조와는 다른점이 있었습니다..!도메인 모델은 강의에서 말씀하신 개념과 격벽그리고 행동에 대해 적절하게 표현하기위한 객체이지만 핵심 비즈니스 로직을 모두 포함하고 있는게 아니라 대부분 조회된 데이터를 개념에 맞게 변경하는 DTO? 역할을 하는것 같고 상태변경에 대한 로직은 엔티티에 구현하고 service 레이어에서 호출하는 방식으로 보여집니다그렇지만 처음 보는 코드가 잘 읽힐정도로 충분히 설득력있는 구조라고 생각이 듭니다..다만 테스트 코드가 있어야만 그 설득력이 완벽해질것 같다는 생각이 들었습니다그래서 해당 프로젝트 구조를 더 이해하고 학습하기위해 테스트 코드를 작성해보려고 합니다만약 저라면 ~Entity에 작성되어있는 상태변경에 대한 테스트 코드와 ~Service, ~Handler, ~Manager 등에 작성된 로직에 대한 테스크 코드를 작성할 것 같은데강사님은 이러한 구조에서 테스트 코드를 어디까지 작성하시는지 또는 어떻게 접근하시는지 궁금합니다~!
-
미해결
Nginx 성능 테스트 조언 부탁드립니다 ㅠㅠㅠㅠㅠㅠㅠㅠ
안녕하세요, Nginx 성능 테스트를 진행 중인데 궁금한 점이 있어 질문드립니다.현재 아래 두 가지 환경에서 정적 콘텐츠 처리 성능 비교 실험을 진행 중입니다.(Tomcat이라고 표현한 것은 Spring Boot 내부 톰캣을 의미합니다!) Windows 환경: 로컬에 Tomcat과 Nginx 모두 설치 후 실행WSL2 환경: WSL2에 Nginx 설치, 로컬(Windows)에 Tomcat 설치저는 당연히 Nginx의 특성(이벤트 드리븐 구조, 커널 수준 I/O 등) 덕분에 Nginx가 Tomcat보다 정적 콘텐츠 처리 속도가 빠를 것이라 예상했습니다.하지만 실제로는 Tomcat 단독과 Nginx + Tomcat 조합 간의 성능 차이가 거의 없었습니다.또한 WSL2에서 실행한 경우 로컬보다 성능이 더 떨어지는 결과가 나왔습니다.이후 원인을 분석해보니 다음과 같은 문제점이 있었습니다.로컬 vs WSL2 비교 자체가 부적절했습니다.비교를 하려면 동일한 환경(예: Docker 컨테이너, VirtualBox, AWS EC2 등) 위에서 실행해야 유의미할 것 같습니다.Windows에서의 Nginx 성능 한계를 간과했습니다.Windows에서는 Nginx가 리눅스처럼 sendfile() 등의 커널 레벨 통신 최적화를 제대로 활용하지 못한다고 합니다.이 때문에 Nginx의 주요 성능 이점을 살리지 못한 것으로 보입니다.제가 궁금한 점은 다음과 같습니다.Nginx와 Tomcat 간 정적 콘텐츠 처리 속도 차이를 제대로 비교하려면 어떤 환경 구성이 적절할까요?이후에는 단순한 정적 처리 속도뿐 아니라, 정적/동적 서버 분리 구조 vs 통합 구조 간의 대규모 트래픽 처리 성능 차이도 테스트하고 싶습니다.마지막으로, HTTPS(SSL 인증서) 적용 시 성능 차이도 함께 측정해보고 싶습니다.혹시 다른 분들은 회사가 아닌, 개인적으로 이런 성능 테스트를 하실 때, 어떤 환경(예: Docker, EC2, VM 등)에서 비교를 진행하시는지 조언을 부탁드립니다 🙏
-
해결됨제미니의 개발실무 - 커머스 백엔드 기본편
서비스의 테스트에 관하여...
안녕하세요!리뷰 쪽 강의를 듣다가 궁금한 점이 있어 질문드립니다.강의에서는 findReviews를 제외하고 나머지 기능은 Implement Layer를 통해 각각 값을 전달하는 구조로 되어 있는 것 같습니다.저도 코드 응집도를 높이기 위해 비슷한 구조를 사용 할때가 있는데 실제로는 ReviewService가 여러 작은 서비스에 위임하는 퍼사드 역할을 하게 되는 경우가 있습니다.이런 퍼사드 서비스는 테스트를 어떻게 하는 것이 좋을지 고민입니다. 제가 생각하기에는,1. 통합 테스트를 통해 전체 흐름을 검증하거나2. 각 작은 서비스들을 목(Mock) 혹은 페이크로 대체하여 호출만 검증하는 방법이 가능할 것 같은데 어느 방법이 더 적합한지 확신이 없어 질문드립니다.
-
해결됨350개의 개인 앱을 만들어 월급의 7배 수익을 달성한 방법
구글 플레이 스토어 테스트 계정에 대해서 질문 드립니다.
앱을 제작했는데, 배포 전에 궁금해서 여쭤봅니다.구글 플레이에 앱을 출시하려면 테스트 계정 20명을 등록해줘야한다고 하는데요이건 기준이 어떻게 되나요? 매번 앱을 초기 배포할 때마다 테스트 계정 20명을 등록해야한다.개발자 계정 당 한 번만 테스트 계정 20명을 등록해야한다.개발자 계정과는 무관하고 구글 계정만 있으면 테스트 계정 20명 등록은 한 번만 하면 된다. 셋 중에 어느 것이 실제 해당하게 되나요? 예전에 만든 개발자 계정은 관련 없다는데미리 개발자 계정을 만들어 두지 않은 것을 후회합니다 ㅜ
-
미해결Java/Spring 테스트를 추가하고 싶은 개발자들의 오답노트
의존성 역전으로 해결한 외부의존성?
의존성과 Testability(2) 5분 10초 내용입니다.사진과 같이 해결하면 결국 SystemClockHolder의 getMillis에는 Clock이라는 의존성이 숨겨진거 아닌가요? 그럼 이 getMillis 메소드를 테스트하기 힘들어진 게 아닌가요?
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 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를 이용하고 있는데, 혹시 이것이 원인은 아니겠지요..? 스프링이 처음이라 정말 막막한데 항상 많은 도움주셔서 감사합니다.