[Spring boot] TDD로 실제 프로젝트 진행해보기 - 알라딘 책 검색
TDD로 프로젝트 진행하기 1
- TDD의 원리는 간단하다.
- 반드시 실패하는 단위 테스트 코드를 작성한다.
- 테스트 코드를 통과하기 위한 최소한의 구현 코드를 작성한다.
- 구현 코드를 리팩토링한다.
- 3가지 단계를 반복하는 연습을 코드워즈 문제를 풀면서 연습했다. 그런데 실제 프로젝트에서는 어떻게 적용할 수 있을까? 생각해보면 어렵다 잘 모르겠다.
- 간단한 게시판 구현에 있어서도 Spring boot 프로젝트를 실행했을 때, Controller에서 RequestMapping으로 url설정도 localhost:8080/index.html 등으로 설정 했는데 막상 테스트를 생각해보면 내가 chrome을 켜서 주소창에 url을 입력하여 테스트한다.
- TDD는 분명 테스트 코드를 먼저 작성하고 구현코드를 작성하는데 이런 테스트들은 브라우저에서 url을 입력해야하고.. 갑자기 혼란이온다..;; ㅜ
- 짝 프로그래밍을 통해 개발자 선배들한테 배운 TDD를 다시 혼자 해보자.
알라딘 책 검색
1. 책 검색을 했을 때 검색목록에 결과가 없을 경우
-
우선 프로젝트를 생성하고, BookSearch라는 클래스를 생성하고, 테스트 코드를 작성한다.
-
테스트 코드 1
@Test @DisplayName("알라딘 도서 검색창에 책을 검색했을때 결과가 나오지 않으면 No를 리턴한다.") public void testShouldReturnNoWhenNotExistBookInAladin() { // Given: 없는 책을 검색한다. (아무것도 입력안함) // When: searchBook 메서드를 호출한다. String actual = bookSearch.searchBook(given); // Then: No를 리턴한다. assertEquals("No", actual); }
- 이러고 생각해보니까 없는 책을 검색하려면 어떻게 해야할까?.. 크롤링을 사용해서 해당 페이지를 파싱해야 하면 되지 않을까?
-
테스트 코드 2
@Test @DisplayName("알라딘 도서 검색창에 책을 검색했을때 결과가 나오지 않으면 No를 리턴한다.") public void testShouldReturnNoWhenNotExistBookInAladin() throws IOException { // Given: 없는 책을 검색한다. (아무것도 입력안함) Document given = Jsoup.connect("https://www.aladin.co.kr/search/wsearchresult.aspx?SearchTarget=All&SearchWord=&x=0&y=0").get(); // When: searchBook 메서드를 호출한다. String actual = bookSearch.searchBook(given); // Then: No를 리턴한다. assertEquals("No", actual); }
- Jsoup 라이브러리를 이용해서 해당 url에 대한 페이지를 크롤링했다. Jsoup라이브러리 사용은 나중에 다시 다루고, 일단은
connect()
메서드와get()
메서드를 통해 해당 url를 get방식으로 request를 보낸다고만 알고있자.
- Jsoup 라이브러리를 이용해서 해당 url에 대한 페이지를 크롤링했다. Jsoup라이브러리 사용은 나중에 다시 다루고, 일단은
-
실제 코드
import org.jsoup.nodes.Document; public class BookSearch { public String searchBook(Document given) { return "No"; } }
-
리팩토링 - 크롤링해온 html 페이지에서 0건의 상품이 검색되었다고 출력이 되면 “No”를 출력하도록 한다.
- 0 건의 상품이 검색되었다는 텍스트는 <div class=”serach_t_g”… 태그에서 볼 수 있다. Document given을 이용하여 코드를 리팩토링 해보자.
import org.jsoup.nodes.Document; public class BookSearch { public String searchBook(Document given) { if (given.select("div.search_t_g").text().contains("0 건의")) { return "No"; } return ""; } }
select()
메서드를 통해 태그를 가져올 수 있다. 태그 내용을text()
메서드와contains()
메서드를 통해 “0 건”이라는 string이 있다면 No를 출력하도록 했다.- 일단은 이정도로 끝낼 수 있을것 같다. 다음 테스트 고고
2. 책 검색을 했을 때 검색목록에 검색 결과가 있을 경우
-
“refactoring”이라는 책을 검색했을때 결과창을 보면
- 검색 목록이 출력되며 해당 html 태그는 <div id=”Search_Result”…이다. 이 태그는 검색 결과가 있을때만 있는 태그이다. 이제 테스트 코드를 짜보자
-
테스트 코드
@Test @DisplayName("알라딘 도서 검색창에 책을 검색했을때 결과가 나오면 Yes를 리턴한다.") public void testShouldReturnYesWhenNotExistBookInAladin() throws IOException { // Given: 없는 책을 검색한다. (refactoring) Document given = Jsoup.connect("https://www.aladin.co.kr/search/wsearchresult.aspx?SearchTarget=All&SearchWord=refactoring&x=0&y=0").get(); // When: searchBook 메서드를 호출한다. String actual = bookSearch.searchBook(given); // Then: Yes를 리턴한다. assertEquals("Yes", actual); }
-
실제 코드
import org.jsoup.nodes.Document; public class BookSearch { public String searchBook(Document given) { if (given.select("div.search_t_g").text().contains("0 건의")) { return "No"; } return "Yes"; } }
-
리팩토링 1 - 검색했을때 결과가 있다면 <div id=”Search3_Result”.. 태그가 있으니까 이 태그가 존재한다면 Yes를 리턴한다고 해보자
import org.jsoup.nodes.Document; public class BookSearch { public String searchBook(Document given) { if (given.select("div.search_t_g").text().contains("0 건")) { return "No"; } if(given.select("div#Search3_Result").size()>0) { return "Yes"; } return ""; } }
-
리팩토링 2 - if문을 두가지로 나누지 말고,
select("div#Search3_Result")
의 결과가 없다면 size가 0일 테니까 if문을 줄여보자.import org.jsoup.nodes.Document; public class BookSearch { public String searchBook(Document given) { if(given.select("div#Search3_Result").size()==0) { return "No"; } return "Yes"; } }
- 일단 이정도로도 됐다. 이것만 봤을때는 내가 평소에 코드워즈 문제 풀었을때랑 크게 다른게 없다. 생각해 볼 수 있는것은 테스트 코드에서 주어진 given을 실제 구현 코드에서 url구하는 메서드로 추출할 수 있을것 같다..
- 짝 프로그래밍을 할 때, String으로 “Yes”, “No” 출력하도록 하지말고 Json형태로 리턴하도록 하자해서 그 부분에 대한 수정을 다음에 해보자.
댓글남기기