JUNIT-Spring @Asyncvoid 서비스 방법
봄맞이 서비스가 있습니다.
@Service
@Transactional
public class SomeService {
@Async
public void asyncMethod(Foo foo) {
// processing takes significant time
}
}
그리고 이것에 대한 통합 테스트가 있습니다.SomeService
:
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@Transactional
public class SomeServiceIntTest {
@Inject
private SomeService someService;
@Test
public void testAsyncMethod() {
Foo testData = prepareTestData();
someService.asyncMethod(testData);
verifyResults();
}
// verifyResult() with assertions, etc.
}
문제는 다음과 같습니다.
- ~하듯이
SomeService.asyncMethod(..)
주석이 달렸습니다.@Async
그리고. - 처럼
SpringJUnit4ClassRunner
을 고수하는@Async
의미론
그testAsyncMethod
실이 통화를 포크할 것입니다.someService.asyncMethod(testData)
자체 워커 스레드에 입력한 다음 직접 실행을 계속합니다.verifyResults()
, 이전 작업자 스레드가 작업을 완료하기 전에 가능합니다.
어떻게 하면 기다릴 수 있을까요?someService.asyncMethod(testData)
결과를 확인하기 전에 완료할 수 있습니까?스프링 4 및 주석을 사용하여 비동기 동작을 확인하는 단위 테스트를 작성하는 방법에 대한 솔루션을 참조하십시오.여기에 해당하지 않습니다.someService.asyncMethod(testData)
돌아온다void
, 한푼도Future<?>
.
위해서@Async
의미론을 고수할 것이고, 일부 활성 클래스는 주석을 가질 것입니다. 예를 들어.
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
//
}
문제를 해결하기 위해 새로운 Spring 프로필을 소개했습니다.non-async
.
만약에non-async
프로파일이 활성화되어 있지 않습니다.AsyncConfiguration
사용됩니다.
@Configuration
@EnableAsync
@EnableScheduling
@Profile("!non-async")
public class AsyncConfiguration implements AsyncConfigurer {
// this configuration will be active as long as profile "non-async" is not (!) active
}
비동기 프로파일이 활성인 경우NonAsyncConfiguration
사용됩니다.
@Configuration
// notice the missing @EnableAsync annotation
@EnableScheduling
@Profile("non-async")
public class NonAsyncConfiguration {
// this configuration will be active as long as profile "non-async" is active
}
이제 문제가 있는 Junit 테스트 클래스에서는 비동기 동작을 상호 제외하기 위해 "비동기" 프로파일을 명시적으로 활성화합니다.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
@WebAppConfiguration
@IntegrationTest
@Transactional
@ActiveProfiles(profiles = "non-async")
public class SomeServiceIntTest {
@Inject
private SomeService someService;
@Test
public void testAsyncMethod() {
Foo testData = prepareTestData();
someService.asyncMethod(testData);
verifyResults();
}
// verifyResult() with assertions, etc.
}
Mockito를 사용하는 경우(직접 또는 Spring 테스트 지원을 통해)@MockBean
), 이 경우에 정확하게 타임아웃되는 검증 모드가 있습니다. https://static.javadoc.io/org.mockito/mockito-core/2.10.0/org/mockito/Mockito.html#22
someAsyncCall();
verify(mock, timeout(100)).someMethod();
훨씬 더 유능한 것은 비동기 주장을 처리하는 방법이 많은 훌륭한 라이브러리 웨이틸리티입니다.예:
someAsyncCall();
await().atMost(5, SECONDS)
.untilAsserted(() -> assertThat(userRepo.size()).isEqualTo(1));
ThreadPoolTask를 주입했습니다.실행자
그리고 나서.
실행자.getThreadPoolExecutor().waitTermination(1, TimeUnit).세컨즈);
결과를 확인하기 전에 다음과 같이 합니다.
@Autowired
private ThreadPoolTaskExecutor executor;
@Test
public void testAsyncMethod() {
Foo testData = prepareTestData();
someService.asyncMethod(testData);
executor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);
verifyResults();
}
메소드가 반환되는 경우CompletableFuture
사용하다join
method - documentation Complete미래:: 가입.
이 메서드는 비동기 메서드가 완료될 때까지 기다렸다가 결과를 반환합니다.발생한 예외는 기본 스레드에서 다시 생성됩니다.
단지 @bastiat에 의한 답을 확장하기 위해, 내 생각에 올바른 것으로 여겨져야 할 것이고, 당신은 또한 다음을 명시해야 합니다.TaskExecutor
, 여러 실행자와 함께 작업하는 경우.그래서 당신이 기다리고 싶은 정확한 주사를 맞아야 합니다.다음과 같은 구성 클래스가 있다고 가정해 보겠습니다.
@Configuration
@EnableAsync
public class AsyncConfiguration {
@Bean("myTaskExecutor")
public TaskExecutor myTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(15);
executor.setCoreCapacity(10);
executor.setQueueCapacity(Integer.MAX_VALUE);
executor.setThreadNamePrefix("MyTaskExecutor-");
executor.initialize();
return executor;
}
// Everything else
}
그러면 다음과 같은 서비스가 제공됩니다.
@Service
public class SomeServiceImplementation {
@Async("myTaskExecutor")
public void asyncMethod() {
// Do something
}
// Everything else
}
@bastiat 답변을 확장하면 테스트는 다음과 같습니다.
@Autowired
private SomeService someService;
@Autowired
private ThreadPoolTaskExecutor myTaskExecutor;
@Test
public void testAsyncMethod() {
Foo testData = prepareTestData();
this.someService.asyncMethod(testData);
this.myTaskExecutor.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);
this.verifyResults();
// Everything else
}
그리고 질문과 상관없는 사소한 추천이 있습니다.는 추가하지 @Transactional
서비스에 대한 주석, DAO/리포지토리에만 주석을 달 수 있습니다.원자성이어야 하는 특정 서비스 방법에 추가할 필요가 없는 경우.
위의 솔루션에 추가하면 됩니다.
@Autowired
private ThreadPoolTaskExecutor pool;
@Test
public void testAsyncMethod() {
// call async method
someService.asyncMethod(testData);
boolean awaitTermination = pool.getThreadPoolExecutor().awaitTermination(1, TimeUnit.SECONDS);
assertThat(awaitTermination).isFalse();
// verify results
}
언급URL : https://stackoverflow.com/questions/42438862/junit-testing-a-spring-async-void-service-method
'programing' 카테고리의 다른 글
Node.js 스크립트에 적합한 hashbang (0) | 2023.09.06 |
---|---|
jQuery Data() API를 사용하여 데이터 속성을 설정할 수 없습니다. (0) | 2023.09.06 |
jquery를 한 기능이 끝날 때까지 기다렸다가 다른 기능을 실행하려면 어떻게 해야 합니까? (0) | 2023.09.06 |
특별한 경우:%보다 빠릅니까? (0) | 2023.09.06 |
PowerShell 매개 변수 값 목록 (0) | 2023.09.06 |