-
Notifications
You must be signed in to change notification settings - Fork 47
Step2 Acceptance Test 기반 구현 #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: decaffeine
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,27 @@ | ||
| package nextstep.web; | ||
|
|
||
| import nextstep.domain.Question; | ||
| import nextstep.service.QnaService; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.web.bind.annotation.GetMapping; | ||
|
|
||
| import javax.annotation.Resource; | ||
| import java.util.ArrayList; | ||
| import java.util.Iterator; | ||
| import java.util.List; | ||
|
|
||
| @Controller | ||
| public class HomeController { | ||
|
|
||
| @Resource(name = "qnaService") | ||
| private QnaService qnaService; | ||
| @GetMapping("/") | ||
| public String home(Model model) { | ||
| Iterable<Question> questionsIterable = qnaService.findAll(); | ||
| List<Question> questions = new ArrayList<>(); | ||
| questionsIterable.forEach(questions::add); | ||
| model.addAttribute("questions",questions); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굳이 새로운 List에 담기보다 questionsIterable을 그냥 전달해도 되지 않을까? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. space convention 위반 |
||
| return "home"; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| package nextstep.web; | ||
|
|
||
| import nextstep.UnAuthenticationException; | ||
| import nextstep.domain.User; | ||
| import nextstep.security.HttpSessionUtils; | ||
| import nextstep.service.UserService; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
|
|
||
| import javax.servlet.http.HttpSession; | ||
|
|
||
| public class LoginController { | ||
|
|
||
| @Autowired | ||
| private UserService userService; | ||
|
|
||
| @PostMapping("/login") | ||
| public String login(String userId, String password, HttpSession session) throws UnAuthenticationException { | ||
| User loginUser = userService.login(userId, password); | ||
| session.setAttribute(HttpSessionUtils.USER_SESSION_KEY, loginUser); | ||
| return "redirect:/"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 로그인 실패하는 경우에 대한 예외처리도 하면 좋지 않을까? |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| package nextstep.web; | ||
|
|
||
| import nextstep.CannotDeleteException; | ||
| import nextstep.UnAuthorizedException; | ||
| import nextstep.domain.Question; | ||
| import nextstep.domain.QuestionRepository; | ||
| import nextstep.domain.User; | ||
| import nextstep.security.LoginUser; | ||
| import nextstep.service.QnaService; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.data.domain.Pageable; | ||
| import org.springframework.stereotype.Controller; | ||
| import org.springframework.ui.Model; | ||
| import org.springframework.web.bind.annotation.*; | ||
|
|
||
| import javax.annotation.Resource; | ||
| import javax.persistence.EntityNotFoundException; | ||
| import javax.transaction.Transactional; | ||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| @Controller | ||
| @RequestMapping("/questions") | ||
| public class QuestionController { | ||
|
|
||
| private static final Logger log = LoggerFactory.getLogger(QuestionController.class); | ||
|
|
||
| @Resource(name = "qnaService") | ||
| private QnaService qnaService; | ||
|
|
||
| @Resource(name = "questionRepository") | ||
| private QuestionRepository questionRepository; | ||
|
|
||
|
|
||
| @GetMapping("/form") | ||
| public String form() { return "/qna/form"; } | ||
|
|
||
| @PostMapping("") | ||
| public String create(Question question, @LoginUser User loginUser) { | ||
| qnaService.create(loginUser, question); | ||
| return "redirect:/questions"; | ||
| } | ||
|
|
||
| @GetMapping("") | ||
| public String list(Model model) { | ||
| List<Question> questions = new ArrayList<>(); | ||
| Iterable<Question> questionsIterable = qnaService.findAll(); | ||
| questionsIterable.iterator().forEachRemaining(questions::add); | ||
| model.addAttribute("questions", questions); | ||
| return "home"; | ||
| } | ||
|
|
||
| @GetMapping("/{id}") | ||
| public String showDetailQuestion(@PathVariable Long id, Model model) { | ||
| Question question = qnaService.findById(id).orElseThrow(EntityNotFoundException::new); | ||
| model.addAttribute("question", question); | ||
| return "/qna/show"; | ||
| } | ||
|
|
||
| @PostMapping("/{id}") | ||
| public String update(@LoginUser User loginUser, @PathVariable long id, Question question) throws UnAuthorizedException{ | ||
| qnaService.update(loginUser, id, question); | ||
| return "redirect:/questions"; | ||
| } | ||
|
|
||
| @GetMapping("/{id}/form") | ||
| public String formForUpdate(@LoginUser User loginUser, @PathVariable long id, Model model) { | ||
| Question question = qnaService.findById(id).orElseThrow(EntityNotFoundException::new); | ||
| if (!question.isOwner(loginUser)) { | ||
| throw new UnAuthorizedException(); | ||
| } | ||
| model.addAttribute("question", question); | ||
| return "/qna/updateForm"; | ||
| } | ||
|
|
||
| @DeleteMapping("/{id}") | ||
| public String delete(@LoginUser User loginUser, @PathVariable long id) throws CannotDeleteException { | ||
| qnaService.deleteQuestion(loginUser, id); | ||
| return "redirect:/questions"; | ||
| } | ||
|
|
||
|
|
||
|
|
||
|
|
||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package nextstep.web; | ||
|
|
||
| import org.junit.Test; | ||
| import org.springframework.http.HttpEntity; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.util.MultiValueMap; | ||
| import support.test.AcceptanceTest; | ||
| import support.test.HtmlFormDataBuilder; | ||
|
|
||
| public class LoginAcceptanceTest extends AcceptanceTest { | ||
|
|
||
| @Test | ||
| public void login() { | ||
| HttpEntity<MultiValueMap<String, Object>> request = HtmlFormDataBuilder.urlEncodedForm() | ||
| .addParameter("userId", "javajigi") | ||
| .addParameter("password", "test") | ||
| .build(); | ||
| ResponseEntity<String> response = template().postForEntity("/login", request, String.class); | ||
|
|
||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FOUND); | ||
| softly.assertThat(response.getHeaders().getLocation().getPath()).startsWith("/"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| package nextstep.web; | ||
|
|
||
| import nextstep.domain.QuestionRepository; | ||
| import nextstep.domain.User; | ||
| import org.junit.Test; | ||
| import org.slf4j.Logger; | ||
| import org.slf4j.LoggerFactory; | ||
| import org.springframework.beans.factory.annotation.Autowired; | ||
| import org.springframework.boot.test.web.client.TestRestTemplate; | ||
| import org.springframework.http.HttpEntity; | ||
| import org.springframework.http.HttpStatus; | ||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.util.MultiValueMap; | ||
| import support.test.AcceptanceTest; | ||
| import support.test.HtmlFormDataBuilder; | ||
|
|
||
| public class QuestionAcceptanceTest extends AcceptanceTest { | ||
| private static final Logger log = LoggerFactory.getLogger(UserAcceptanceTest.class); | ||
|
|
||
| @Autowired | ||
| private QuestionRepository questionRepository; | ||
|
|
||
| @Test | ||
| public void createForm() { | ||
| ResponseEntity<String> response = template().getForEntity("/questions/form", String.class); | ||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); | ||
| log.debug("body : {}", response.getBody()); | ||
| } | ||
|
|
||
| @Test | ||
| public void create() { | ||
| User loginUser = defaultUser(); | ||
| HttpEntity<MultiValueMap<String, Object>> request = HtmlFormDataBuilder.urlEncodedForm() | ||
| .addParameter("title", "테스트") | ||
| .addParameter("contents", "테스트내용") | ||
| .build(); | ||
| ResponseEntity<String> response = basicAuthTemplate(loginUser) | ||
| .postForEntity("/questions", request, String.class); | ||
|
|
||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FOUND); | ||
| softly.assertThat(questionRepository.findById(loginUser.getId()).isPresent()).isTrue(); | ||
| softly.assertThat(response.getHeaders().getLocation().getPath()).startsWith("/questions"); | ||
| } | ||
|
|
||
| @Test | ||
| public void list() { | ||
| ResponseEntity<String> response = template().getForEntity("/questions", String.class); | ||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); | ||
| log.debug("body : {}", response.getBody()); | ||
| softly.assertThat(response.getBody().contains("Ruby")).isTrue(); | ||
| } | ||
|
|
||
| @Test | ||
| public void update() throws Exception { | ||
| ResponseEntity<String> response = update(basicAuthTemplate()); | ||
|
|
||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FOUND); | ||
| softly.assertThat((response.getHeaders().getLocation()).getPath().startsWith("/questions")); | ||
| } | ||
|
|
||
| private ResponseEntity<String> update(TestRestTemplate template) throws Exception { | ||
|
|
||
| HttpEntity<MultiValueMap<String, Object>> request = HtmlFormDataBuilder | ||
| .urlEncodedForm() | ||
| .addParameter("title", "테스트제목") | ||
| .addParameter("contents", "테스트내용") | ||
| .build(); | ||
|
|
||
| return template.postForEntity("/questions/1", request, String.class); | ||
| } | ||
|
|
||
| @Test | ||
| public void delete() { | ||
| HttpEntity request = HtmlFormDataBuilder.urlEncodedForm() | ||
| .addParameter("_method","delete") | ||
| .build(); | ||
| ResponseEntity<String> response = basicAuthTemplate(defaultUser()) | ||
| .postForEntity("/questions/1", request, String.class); | ||
|
|
||
| softly.assertThat(response.getStatusCode()).isEqualTo(HttpStatus.FOUND); | ||
| softly.assertThat((response.getHeaders().getLocation()).getPath().startsWith("/questions")); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 도메인 객체에 로직을 구현했는데 이에 대한 단위 테스트도 구현하면 좋지 않을까? |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍