저는 초보자 인 스프링 프레임 워크입니다. 단위 테스트를 실행하는 동안 스프링 컨텍스트를로드하는 것과 함께 스프링 부팅시 단위 테스트를 구성하는 데 문제가 있습니다. 나는 (팀에서) maven multimodule 프로젝트와 함께이 일을 할 올바른 해결책을 찾고있다.스프링 부트 메이븐 멀티 모듈 프로젝트 - 유닛 테스팅 (어플리케이션 컨텍스트)
- 공유지 (모듈, 포장 : 병, 유틸 모듈)
+ --- SRC
+ ---의 pom.xml - 제안 (모듈을 다음과 같이 내 프로젝트 구조의 부분은 포장 : POM)
- 제안-API (서브 모듈 : 인터페이스, DTO, 포장 : 항아리)
- 제안 매핑 (서브 모듈 : 엔티티)
- 제안-SE rvice (서브 모듈 : 서비스, 스프링 데이터 저장소, DTO - - 엔티티 <> DTO 맵퍼는 제안-API 및 제안 매핑 포장에 따라 달라집니다 항아리)
+ --- SRC
+ --- 주요
+ --- 자바
+ --- com.company.proposal.service
+ --- DeviceRepositoryService.java
+ --- DeviceMapper.java
+ --- ProposalRepositoryService.java
+ --- ProposalMapper.java
+ --- 훨씬 더 클래스 ...
+ --- 시험
+ --- 자바
+ --- com.company.proposal.service
+ --- DeviceRepositoryServiceTest.java
+ --- ProposalRepositoryServiceTest.자바
+ --- ...
+ ---의 pom.xml - 제안 - 스타터 (서브 모듈 : 자동 클래스, 포장 : 항아리)
+ --- SRC
+ --- 주요
+ --- 자바
+ --- com.company.proposal.configuration + ---
ProposalAutoConfiguration.java
+ --- RemoteReportProcessorAutoConfiguration.java
+ --- 다른 구성 클래스 ...
+ --- 자원
+ --- META-INF
+ - - spring.factories
+ --- application.properties
+ ---의 pom.xml
- 엔트리 포인트 (모듈, 포장 : POM)
- 진입 점-API (서브 모듈, 포장 : 항아리)
- 엔트리 포인트 서비스 (서브 모듈, 포장 : 항아리)
- 엔트리 포인트 스타터 (서브 모듈, 포장 : 제이보스에 배포 전쟁)
- 다른-모듈 ...
- 의 pom.xml (루트 POM) 내가 쓴
예 단위 테스트 (DeviceRepositoryServiceTest.java) :
@RunWith(SpringRunner.class)
public class DeviceRepositoryServiceTest {
@Rule
public ExpectedException thrown = ExpectedException.none();
@MockBean
private DeviceRepository deviceRepository;
@Autowired
private DeviceMapper deviceMapper;
private DeviceRepositoryService deviceRepositoryService;
private final String imei = "123456789123456";
private final String producer = "samsung";
private final String model = "s5";
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
deviceRepositoryService = new DeviceRepositoryService(deviceRepository, deviceMapper);
}
@org.springframework.boot.test.context.TestConfiguration
static class TestConfiguration {
@Bean
public DeviceMapper deviceMapper() {
return new DeviceMapperImpl();
}
}
@Test
public void test_should_create_device() {
given(deviceRepository.findByImei(imei)).willReturn(null);
when(deviceRepository.save(any(Device.class))).thenAnswer((Answer) invocation -> invocation.getArguments()[0]);
DeviceSnapshot device = deviceRepositoryService.createOrFindDeviceByImei(imei, producer, model);
assertThat(device.getImei()).isEqualTo(imei);
assertThat(device.getProducer()).isEqualTo(producer);
assertThat(device.getModel()).isEqualTo(model);
verify(deviceRepository, times(1)).save(any(Device.class));
}
@Test
public void test_should_return_device() {
Device testDevice = createTestDevice();
given(deviceRepository.findByImei(imei)).willReturn(testDevice);
DeviceSnapshot actualDevice = deviceRepositoryService
.createOrFindDeviceByImei(testDevice.getImei(), testDevice.getProducer(), testDevice.getModel());
assertThat(actualDevice.getImei()).isEqualTo(testDevice.getImei());
assertThat(actualDevice.getProducer()).isEqualTo(testDevice.getProducer());
assertThat(actualDevice.getModel()).isEqualTo(testDevice.getModel());
verify(deviceRepository, times(0)).save(any(Device.class));
verify(deviceRepository, times(1)).findByImei(testDevice.getImei());
}
@Test
public void test_should_find_device() {
Device device = createTestDevice();
given(deviceRepository.findOne(device.getId())).willReturn(device);
DeviceSnapshot actualDevice = deviceRepositoryService.findDeviceById(device.getId());
DeviceSnapshot expectedDevice = deviceMapper.toDeviceSnapshot(device);
assertThat(actualDevice).isEqualTo(expectedDevice);
verify(deviceRepository, times(1)).findOne(device.getId());
}
@Test
public void test_should_find_device_by_pparams() {
Device device = createTestDevice();
Long proposalId = 1L, providerConfigId = 2L;
given(deviceRepository.findByProposalParams(proposalId, providerConfigId)).willReturn(device);
DeviceSnapshot actualDevice = deviceRepositoryService.findDeviceByProposalParams(proposalId, providerConfigId);
DeviceSnapshot expectedDevice = deviceMapper.toDeviceSnapshot(device);
assertThat(actualDevice).isEqualTo(expectedDevice);
verify(deviceRepository, times(1)).findByProposalParams(proposalId, providerConfigId);
}
@Test
public void test_should_throw_not_found_1() {
given(deviceRepository.findOne(anyLong())).willReturn(null);
this.thrown.expect(DeviceNotFoundException.class);
deviceRepositoryService.findDeviceById(1L);
}
@Test
public void test_should_throw_not_found_2() {
given(deviceRepository.findByProposalParams(anyLong(), anyLong())).willReturn(null);
this.thrown.expect(DeviceNotFoundException.class);
deviceRepositoryService.findDeviceByProposalParams(1L, 1L);
}
private Device createTestDevice() {
return Device.builder()
.id(1L)
.imei(imei)
.model(model)
.producer(producer)
.build();
}
}
당신은 내가 컨텍스트를 정의 할 @TestConfiguration 주석을 사용하여 볼 수 있듯이, 하지만 클래스 DeviceRepositoryService
이 매우 간단하기 때문에 - 단지 2 개의 의존성 때문에 컨텍스트 정의도 간단합니다.위 클래스에서
@Slf4j
@Service
@AllArgsConstructor
@Transactional
public class ProposalRepositoryService implements ProposalService {
private final ProposalRepository proposalRepository;
private final ProposalMapper proposalMapper;
private final ProposalRepositoryProperties repositoryProperties;
private final ImageProposalRepository imageProposalRepository;
private final ProviderConfigService providerConfigService;
...
}
더 의존하고 것은 내가 모든 테스트 (TestConfiguration 주석)에 대한 구성 코드의 무리를 작성하지 않을 것입니다 : 짧은에 다음과 같이 나 또한 보이는 클래스 ProposalRepositoryService
을 테스트해야합니다. 예 : 일부 서비스에 종속성을 추가하면 유닛 테스트 클래스의 절반을 변경해야하며 코드가 반복됩니다. 또한 단위 테스트 코드 때문에 구성 정의의 추악한지고 예를 :
@TestPropertySource("classpath:application-test.properties")
public class RemoteReportProcessorRepositoryServiceTest {
@Autowired
private RemoteReportProcessorRepositoryService remoteReportProcessorRepositoryService;
@TestConfiguration //here, I don't want to write bunch of configuration code for every test
static class TestConfig {
@Bean
@Autowired
public RemoteReportProcessorRepositoryService remoteReportProcessorRepositoryService(RemoteReportMailService remoteReportMailService,
FtpsService ftpsService,
RemoteDailyReportProperties remoteDailyReportProperties,
RemoteMonthlyReportProperties remoteMonthlyReportProperties,
DeviceRepository deviceRepository,
ProposalRepository proposalRepository) {
return new RemoteReportProcessorRepositoryService(ftpsService, remoteReportMailService, remoteDailyReportProperties, remoteMonthlyReportProperties, deviceRepository, proposalRepository);
}
@Bean
@Autowired
public FtpsManagerService ftpsManagerService(FTPSClient ftpsClient, MailService mailService, FtpsProperties ftpsProperties) {
return new FtpsManagerService(ftpsClient, ftpsProperties, mailService);
}
@Bean
public FTPSClient ftpsClient() {
return new FTPSClient();
}
@Bean
@Autowired
public MailService mailService(MailProperties mailProperties, JavaMailSender javaMailSender, PgpProperties pgpProperties) {
return new MailManagerService(mailProperties, javaMailSender, pgpProperties);
}
@Bean
public JavaMailSender javaMailSender() {
return new JavaMailSenderImpl();
}
@Bean
@Autowired
public RemoteReportMailService remoteReportMailService(RemoteReportMailProperties remoteReportMailProperties,
JavaMailSender javaMailSender,
Session session,
PgpProperties pgpProperties) {
return new RemoteReportMailManagerService(remoteReportMailProperties, javaMailSender, session, pgpProperties);
}
@Bean
@Autowired
public Session getJavaMailReceiver(RemoteReportMailProperties remoteReportMailProperties) {
Properties properties = new Properties();
properties.put("mail.imap.host", remoteReportMailProperties.getImapHost());
properties.put("mail.imap.port", remoteReportMailProperties.getImapPort());
properties.setProperty("mail.imap.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
properties.setProperty("mail.imap.socketFactory.fallback", "false");
properties.setProperty("mail.imap.socketFactory.port", remoteReportMailProperties.getImapPort().toString());
properties.put("mail.imap.debug", "true");
properties.put("mail.imap.ssl.trust", "*");
return Session.getDefaultInstance(properties);
}
}
...
}
그래서, 내 질문의 무리를 작성하지 않고, 스프링 부팅 받는다는 멀티 모듈 프로젝트를 올바른 방법으로 단위 테스트를 위해 스프링 컨텍스트를 구성하는 방법입니다 구성 코드? 또한 maven multimodule 프로젝트를 다루는 방법에 대해 자세히 설명 할 때 기사에 대한 링크에 감사드립니다.
Spring 컨텍스트 슬라이스
테스트 공통의 부모 클래스를 만들 수 있습니다. 구성 코드가 들어있는 유사한 테스트 케이스의 경우. – 11thdimension
예제를 보여줄 수 있습니까? 모든 구성 코드를 보유하지만 그 클래스는 다른 모든 모듈 (순환 종속성)에 의존해야하는 한 클래스 (예 : commons 모듈)를 작성할 수 있습니다. – lukascode
부모 클래스 접근 방식으로 시도해보십시오. 원형 의존성 문제는 없을 것이라고 생각합니다. 예를 게시하려고합니다. – 11thdimension