ãã©ã¡ãŒã¿åããããŠããããã¹ãã®ããžã§ã³ããããã©ã®ããã«è¡ããããããŠããããããªããã©ã®ããã«ããªããïŒããããããããïŒãå ±æããããšã«ããŸããã
äœãæ£ãããã¹ããã¹ããã«ã€ããŠçŸãããã¬ãŒãºãæžããããšæããŸãããã¹ãã¯éèŠã§ããããã§ã«å€ãã®è³æãç§ã®åã§èšãããæžãããŠããã®ã§ãç§ã®æèŠã§ã¯ã人ã ããã£ãã«äœ¿çšããªãïŒç解ããïŒãã®ãèŠçŽããŠåŒ·èª¿ããŸããã«ç§»åããŸãã
ãã®èšäºã®äž»ãªç®çã¯ããªããžã§ã¯ããäœæããããã®ã³ãŒãã§ãŠããããã¹ããä¹±éã«ããã®ãé²ãæ¹æ³ïŒããã³ãã¹ãã§ããïŒãšãã¢ãã¯ïŒanyïŒïŒïŒãååã§ãªãããã®ãããªç¶æ³ãããããããå Žåã«ãã¹ãããŒã¿ã宣èšçã«äœæããæ¹æ³ã瀺ãããšã§ãã
mavenãããžã§ã¯ããäœæããjunit5ãjunit-jupiter-paramsãmokitoãè¿œå ããŠã¿ãŸãããã
å®å šã«éå±ã«ãªããªãããã«ããã¹ãããããã«æžãå§ããŸããTDDã®è¬çœªè ã奜ãããã«ã宣èšçã«ãã¹ããããµãŒãã¹ãå¿ èŠã§ãã
ãã¹ãHabrServiceTestãäœæããŸãããããã¹ãã¯ã©ã¹ãã£ãŒã«ãã«HabrServiceãžã®ãªã³ã¯ãè¿œå ããŸãã
public class HabrServiceTest {
private HabrService habrService;
@Test
void handleTest(){
}
}
ideãä»ããŠãµãŒãã¹ãäœæãïŒã·ã§ãŒãã«ããã軜ãæŒãããšã«ããïŒããã£ãŒã«ãã«@InjectMocksã¢ãããŒã·ã§ã³ãè¿œå ããŸãã
ãã¹ãããçŽæ¥å§ããŸããããå°ããªã¢ããªã±ãŒã·ã§ã³ã®HabrServiceã«ã¯ãåäžã®HabrItemåŒæ°ãåãåãåäžã®handleïŒïŒã¡ãœãããããããã¹ãã¯æ¬¡ã®ããã«ãªããŸãã
public class HabrServiceTest {
@InjectMocks
private HabrService habrService;
@Test
void handleTest(){
HabrItem item = new HabrItem();
habrService.handle(item);
}
}
HabrServiceã«handleïŒïŒã¡ãœãããè¿œå ããŠã¿ãŸããããããã¯ãã¢ãã¬ãŒããããŠããŒã¿ããŒã¹ã«ä¿åãããåŸãHabréã®æ°ããæçš¿ã®IDãè¿ããHabrItemã¿ã€ããåããHabrItemãäœæããŸããããã§ããã¹ãã¯ã³ã³ãã€ã«ãããŸãããã¯ã©ãã·ã¥ããŸãã
éèŠãªã®ã¯ãæåŸ ãããæ»ãå€ã®ãã§ãã¯ãè¿œå ããããšã§ãã
public class HabrServiceTest {
@InjectMocks
private HabrService habrService;
@BeforeEach
void setUp(){
initMocks(this);
}
@Test
void handleTest() {
HabrItem item = new HabrItem();
Long actual = habrService.handle(item);
assertEquals(1L, actual);
}
}
ãŸããhandleïŒïŒã¡ãœããã®åŒã³åºãäžã«ãReviewServiceãšPersistanceServiceãåŒã³åºãããå³å¯ã«æ¬¡ã ã«åŒã³åºããã1åã ãæ©èœããä»ã®ã¡ãœãããåŒã³åºãããªããªã£ãããšã確èªããããšæããŸããèšãæããã°ããã®ããã«ïŒ
public class HabrServiceTest {
@InjectMocks
private HabrService habrService;
@BeforeEach
void setUp(){
initMocks(this);
}
@Test
void handleTest() {
HabrItem item = new HabrItem();
Long actual = habrService.handle(item);
InOrder inOrder = Mockito.inOrder(reviewService, persistenceService);
inOrder.verify(reviewService).makeRewiew(item);
inOrder.verify(persistenceService).makePersist(item);
inOrder.verifyNoMoreInteractions();
assertEquals(1L, actual);
}
}
ã¯ã©ã¹ã¯ã©ã¹ã®ãã£ãŒã«ãã«reviewServiceã¡ãœãããšpersistenceServiceãè¿œå ããããããäœæããmakeRewiewïŒïŒã¡ãœãããšmakePersistïŒïŒã¡ãœãããããããè¿œå ããŸããããã§ãã¹ãŠãã³ã³ãã€ã«ãããŸããããã¡ãããã¹ãã¯èµ€ã§ãã
ãã®èšäºã®ã³ã³ããã¹ãã§ã¯ãReviewServiceãšPersistanceServiceã®å®è£ ã¯ããã»ã©éèŠã§ã¯ãªããHabrServiceã®å®è£ ã¯éèŠã§ããä»ãããå°ãé¢çœãããŸãããã
public class HabrService {
private final ReviewService reviewService;
private final PersistenceService persistenceService;
public HabrService(final ReviewService reviewService, final PersistenceService persistenceService) {
this.reviewService = reviewService;
this.persistenceService = persistenceService;
}
public Long handle(final HabrItem item) {
HabrItem reviewedItem = reviewService.makeRewiew(item);
Long persistedItemId = persistenceService.makePersist(reviewedItem);
return persistedItemId;
}
}
ãããŠãwhenïŒïŒãthenïŒïŒæ§æã䜿çšããŠãè£å©ã³ã³ããŒãã³ãã®åäœãããã¯ããŸãããã®çµæããã¹ãã¯æ¬¡ã®ããã«ãªããç·è²ã«ãªããŸãã
public class HabrServiceTest {
@Mock
private ReviewService reviewService;
@Mock
private PersistenceService persistenceService;
@InjectMocks
private HabrService habrService;
@BeforeEach
void setUp() {
initMocks(this);
}
@Test
void handleTest() {
HabrItem source = new HabrItem();
HabrItem reviewedItem = mock(HabrItem.class);
when(reviewService.makeRewiew(source)).thenReturn(reviewedItem);
when(persistenceService.makePersist(reviewedItem)).thenReturn(1L);
Long actual = habrService.handle(source);
InOrder inOrder = Mockito.inOrder(reviewService, persistenceService);
inOrder.verify(reviewService).makeRewiew(source);
inOrder.verify(persistenceService).makePersist(reviewedItem);
inOrder.verifyNoMoreInteractions();
assertEquals(1L, actual);
}
}
ãã©ã¡ãŒã¿åããããã¹ãã®åãå®èšŒããããã®ã¢ãã¯ã¢ãããçšæãããŠããŸãã
ããã¿ã€ãhubTypeã®ãã£ãŒã«ããHabrItemãµãŒãã¹ã®ãªã¯ãšã¹ãã¢ãã«ã«è¿œå ããåæåHubTypeãäœæããŠãããã€ãã®ã¿ã€ããå«ããŸãã
public enum HubType {
JAVA, C, PYTHON
}
HabrItemã¢ãã«ã®å ŽåãäœæãããHubTypeãã£ãŒã«ãã«ã²ãã¿ãŒãšã»ãã¿ãŒãè¿œå ããŸãã
HabrServiceã®æ·±éšã«ã¹ã€ãããé ãããŠãããšããŸããããã¯ãããã®ã¿ã€ãã«å¿ããŠããªã¯ãšã¹ãã§äžæãªåŠçãå®è¡ããŸããäžæãªã±ãŒã¹ããããããã¹ããããã¹ãã§ã¯ãã¡ãœããã®åçŽãªå®è£ ã¯æ¬¡ã®ããã«ãªããŸãã
@Test
void handleTest() {
HabrItem reviewedItem = mock(HabrItem.class);
HabrItem source = new HabrItem();
source.setHubType(HubType.JAVA);
when(reviewService.makeRewiew(source)).thenReturn(reviewedItem);
when(persistenceService.makePersist(reviewedItem)).thenReturn(1L);
Long actual = habrService.handle(source);
InOrder inOrder = Mockito.inOrder(reviewService, persistenceService);
inOrder.verify(reviewService).makeRewiew(source);
inOrder.verify(persistenceService).makePersist(reviewedItem);
inOrder.verifyNoMoreInteractions();
assertEquals(1L, actual);
}
ãã¹ãããã©ã¡ãŒã¿åããåæåããã©ã³ãã ãªå€ããã©ã¡ãŒã¿ãšããŠè¿œå ããããšã§ãå°ããããã§äŸ¿å©ã«ããããšãã§ããŸãããã®çµæããã¹ã宣èšã¯æ¬¡ã®ããã«ãªããŸãã
@ParameterizedTest
@EnumSource(HubType.class)
void handleTest(final HubType type)
ããŸãã宣èšçã«ããããŠç§ãã¡ã®åæã®ãã¹ãŠã®å€ã¯ééããªã次ã®ãã¹ãã®å®è¡ã§äœ¿çšãããŸãã泚éã«ã¯ãã©ã¡ãŒã¿ãŒããããå å«ãé€å€ã®æŠç¥ãè¿œå ã§ããŸãã
ããããããããç§ã¯ããã©ã¡ãŒã¿åããããã¹ããåªããŠãããšããªãã«ç¢ºä¿¡ãããŠããŸãããè¿œå
å ã®HabrItemãªã¯ãšã¹ãã¯æ°ããeditCountãã£ãŒã«ãã§ãããHabrãŠãŒã¶ãŒãèšäºãç·šéããæ°ååãæçš¿åã«æžã蟌ãŸãããããå°ãªããšãå°ãã¯æ°ã«å ¥ã£ãŠããã ããŸããHabrServiceã®å¥¥ã®ã©ããã«ãæªç¥ã®ããšãè¡ãäœããã®ããžãã¯ããããšæ³å®ããŸããäœæè ãè©Šããéã«å¿ããŠãèãããããã¹ãŠã®editCountãªãã·ã§ã³ã«å¯ŸããŠ5ã€ãŸãã¯55ã®ãã¹ããèšè¿°ããããªããã宣èšçã«ãã¹ããããå Žåã¯ã©ããªããŸããïŒ1ã€ã®å Žæã®ã©ããã«ã確èªããããã¹ãŠã®å€ãããã«ç€ºããŸã..ããã以äžç°¡åãªãã®ã¯ãããŸããããã©ã¡ãŒã¿åããããã¹ãã®apiã䜿çšãããšãã¡ãœãã宣èšã§æ¬¡ã®ãããªãã®ãåŸãããŸãã
@ParameterizedTest
@ValueSource(ints = {0, 5, 14, 23})
void handleTest(final int type)
åé¡ããããŸãã宣èšçã«äžåºŠã«ãã¹ãã¡ãœãããã©ã¡ãŒã¿ã«2ã€ã®å€ãåéãããã®ã§ããã©ã¡ãŒã¿åããããã¹ãã®å¥ã®åªããã¡ãœãã@CsvSourceã䜿çšã§ããŸããããã¯ãåçŽãªåºåå€ïŒãŠãŒãã£ãªãã£ã¯ã©ã¹ã®ãã¹ãã«éåžžã«äŸ¿å©ïŒã§ãåçŽãªãã©ã¡ãŒã¿ã®ãã¹ãã«æé©ã§ããããªããžã§ã¯ããã¯ããã«è€éã«ãªã£ãå Žåã¯ã©ããªããŸããïŒããªããã£ããšJavaã¿ã€ãã ãã§ãªããçŽ10åã®ãã£ãŒã«ãããããšããŸãããã
@MethodSourceã¢ãããŒã·ã§ã³ã圹ã«ç«ã¡ããã¹ãã¡ãœãããèããçããªããã»ãã¿ãŒããªããªããçä¿¡èŠæ±ã®ãœãŒã¹ããã©ã¡ãŒã¿ãŒãšããŠãã¹ãã¡ãœããã«éãããŸãã
@ParameterizedTest
@MethodSource("generateSource")
void handleTest(final HabrItem source) {
HabrItem reviewedItem = mock(HabrItem.class);
when(reviewService.makeRewiew(source)).thenReturn(reviewedItem);
when(persistenceService.makePersist(reviewedItem)).thenReturn(1L);
Long actual = habrService.handle(source);
InOrder inOrder = Mockito.inOrder(reviewService, persistenceService);
inOrder.verify(reviewService).makeRewiew(source);
inOrder.verify(persistenceService).makePersist(reviewedItem);
inOrder.verifyNoMoreInteractions();
assertEquals(1L, actual);
}
@MethodSourceã¢ãããŒã·ã§ã³ã«ã¯generateSourceæååããããŸãããããã¯äœã§ããïŒããã¯ãå¿ èŠãªã¢ãã«ãåéããã¡ãœããã®ååã§ãããã®å®£èšã¯æ¬¡ã®ããã«ãªããŸãã
private static Stream<Arguments> generateSource() {
HabrItem habrItem = new HabrItem();
habrItem.setHubType(HubType.JAVA);
habrItem.setEditCount(999L);
return nextStream(() -> habrItem);
}
䟿å®äžãnextStreamåŒæ°ã®ã¹ããªãŒã ã®åœ¢æãå¥ã®ãŠãŒãã£ãªãã£ãã¹ãã¯ã©ã¹ã«ç§»åããŸããã
public class CommonTestUtil {
private static final Random RANDOM = new Random();
public static <T> Stream<Arguments> nextStream(final Supplier<T> supplier) {
return Stream.generate(() -> Arguments.of(supplier.get())).limit(nextIntBetween(1, 10));
}
public static int nextIntBetween(final int min, final int max) {
return RANDOM.nextInt(max - min + 1) + min;
}
}
ããã§ããã¹ããéå§ãããšãHabrItemãªã¯ãšã¹ãã¢ãã«ã宣èšçã«ãã¹ãã¡ãœãããã©ã¡ãŒã¿ã«è¿œå ããããã¹ãã¯ãã¹ããŠãŒãã£ãªãã£ã«ãã£ãŠçæãããåŒæ°ã®æ°ïŒ
ãã®å Žåã¯1ãã10ïŒã§å®è¡ãããŸããããã¯ãã¢ãã«ãåŒæ°ã®ã¹ããªãŒã ã«ããå Žåã«ç¹ã«äŸ¿å©ã§ãããã®äŸã®ããã«ããŒãã³ãŒãã§ã¯ãªããã©ã³ããã€ã¶ãŒã䜿çšããŠåéãããŸãïŒé·çããããããŒãã£ã³ã°ãã¹ãã§ãããããã§ããå Žåã¯åé¡ããããŸãïŒã
ç§ã®æèŠã§ã¯ããã¹ãŠããã§ã«ã¹ãŒããŒã§ããããã¹ãã¯çŸåšãã¹ã¿ãã®åäœãšæåŸ ãããçµæã®ã¿ãèšè¿°ããŠããŸãã
ãããããããäžéã§ããæ°ãããã£ãŒã«ããããã¹ããæååã®é åãHabrItemã¢ãã«ã«è¿œå ãããŸããããã¯ãéåžžã«å€§ããå Žåãšããã§ãªãå ŽåããããŸããåé¡ã§ã¯ãããŸãããäž»ãªããšã¯ããã¹ããä¹±éã«ããããªããã©ã³ãã ããŒã¿ã¯å¿ èŠãªããå³å¯ã«å®çŸ©ãããã¢ãã«ãå¿ èŠãªããšã§ããç¹å®ã®ããŒã¿ã䜿çšããŠããã¹ããŸãã¯ãã®ä»ã®å Žæã§ãããåéããŸã-ç§ãã¡ã¯æãã§ããŸãããéµäŸ¿é éå¡ãªã©ãã©ãããã§ãjsonãªã¯ãšã¹ãã®æ¬æãååŸããããã«åºã¥ããŠã¢ãã¯ãã¡ã€ã«ãäœæãããã¹ãã§å®£èšçã«ã¢ãã«ãäœæããŠãããŒã¿ãå«ãjsonãã¡ã€ã«ãžã®ãã¹ã®ã¿ãæå®ã§ããã°äŸ¿å©ã§ãã
åªç§ãªã @JsonSourceã¢ãããŒã·ã§ã³ã䜿çšããŸããããã¯ãçžå¯Ÿãã¡ã€ã«ãã¹ãšã¿ãŒã²ããã¯ã©ã¹ãšãšãã«ããã¹ãã©ã¡ãŒã¿ãŒãåããŸãããªããŠãã£ãïŒãã©ã¡ãŒã¿åããããã¹ãã«ã¯ãã®ãããªæ³šéã¯ãããŸããããç§ã¯ããã欲ããã§ãã
èªåã§æžããŠã¿ãŸãããã
ArgumentsProviderã¯ãjunitã®@ParametrizedTestã«ä»å±ãããã¹ãŠã®æ³šéã®åŠçãæ åœããŸããç¬èªã®JsonArgumentProviderãèšè¿°ããŸãã
public class JsonArgumentProvider implements ArgumentsProvider, AnnotationConsumer<JsonSource> {
private String path;
private MockDataProvider dataProvider;
private Class<?> clazz;
@Override
public void accept(final JsonSource jsonSource) {
this.path = jsonSource.path();
this.dataProvider = new MockDataProvider(new ObjectMapper());
this.clazz = jsonSource.clazz();
}
@Override
public Stream<Arguments> provideArguments(final ExtensionContext context) {
return nextSingleStream(() -> dataProvider.parseDataObject(path, clazz));
}
}
MockDataProviderã¯ãã¢ãã¯jsonãã¡ã€ã«ã解æããããã®ã¯ã©ã¹ã§ããããã®å®è£ ã¯éåžžã«ç°¡åã§ãã
public class MockDataProvider {
private static final String PATH_PREFIX = "json/";
private final ObjectMapper objectMapper;
public <T> T parseDataObject(final String name, final Class<T> clazz) {
return objectMapper.readValue(new ClassPathResource(PATH_PREFIX + name).getInputStream(), clazz);
}
}
ã¢ãã¯ãããã€ããŒã®æºåãæŽããŸãããã¢ãããŒã·ã§ã³ã®åŒæ°ãããã€ããŒã§ããããŸããã¢ãããŒã·ã§ã³èªäœãè¿œå ããå¿ èŠããããŸãã
/**
* Source- ,
* json-
*/
@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@ArgumentsSource(JsonArgumentProvider.class)
public @interface JsonSource {
/**
* json-, classpath:/json/
*
* @return
*/
String path() default "";
/**
* ,
*
* @return
*/
Class<?> clazz();
}
ãã£ããŒãã¢ãããŒã·ã§ã³ã䜿çšããæºåãæŽããŸããããã¹ãæ¹æ³ã¯æ¬¡ã®ãšããã§ãã
@ParameterizedTest
@JsonSource(path = MOCK_FILE_PATH, clazz = HabrItem.class)
void handleTest(final HabrItem source) {
HabrItem reviewedItem = mock(HabrItem.class);
when(reviewService.makeRewiew(source)).thenReturn(reviewedItem);
when(persistenceService.makePersist(reviewedItem)).thenReturn(1L);
Long actual = habrService.handle(source);
InOrder inOrder = Mockito.inOrder(reviewService, persistenceService);
inOrder.verify(reviewService).makeRewiew(source);
inOrder.verify(persistenceService).makePersist(reviewedItem);
inOrder.verifyNoMoreInteractions();
assertEquals(1L, actual);
}
ã¢ãã¯jsonã§ã¯ãå¿ èŠãªæ°ã®ãªããžã§ã¯ããéåžžã«è¿ éã«äœæã§ããŸããããããã¯ããã¹ãããŒã¿ã®åœ¢æã®ããã«ããã¹ãã®æ¬è³ªãæãªãã³ãŒãã¯ãããŸããããã¡ãããã¢ãã¯ã§å®è¡ã§ããããšã¯ãããããŸãããåžžã«ãããšã¯éããŸããã
èŠçŽãããšãç§ã¯æ¬¡ã®ããã«èšããããšæããŸããç§ãã¡ã¯ãäœå¹Žãã®éãçŸããç°¡åã«ã§ããããšãèããã«ãäœå¹Žãåãšåãããã«ä»äºãããŠããããšããããããŸãã
PSãã®èšäºã¯ãTDDã®æŠå¿µã«é¢ããç¥èãç®çãšãããã®ã§ã¯ãããŸãããã¹ããŒãªãŒããªã³ã°ãã£ã³ããŒã³ã«ãã¹ãããŒã¿ãè¿œå ããŠãããå°ãæ確ã§èå³æ·±ããã®ã«ããããšæããŸããã