이 포스팅의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성한 것이 일부 존재합니다.
thymeleaf를 사용할 때 fragment를 적용하면 HTML 코드의 중복을 줄이고 화면은 리팩토링 전과 똑같이 나오도록 할 수 있다.
간단하게 헤더(header), 네비게이션(nav), 푸터(footer)를 th:replace
라는 문법을 이용할 것이다.
bootstrap 문법이 추가될 수 있습니다.
fragments.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:fragment="header">
...
</head>
<nav th:fragment="main-nav" class="navbar navbar-expand-sm navbar-dark bg-dark">
...
</nav>
<footer th:fragment="footer">
...
</footer>
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head th:replace="fragments.html :: header"></head>
<body class="bg-light">
<nav th:replace="fragments.html :: main-nav"></nav>
<div class="container">
...
<footer th:replace="fragments.html :: footer"></footer>
</div>
</body>
</html>
위의 index.html
코드와 같이 태그 옆에 th:replace를 넣으면 해당 줄은 fragments.html
에서 fragment="footer"
부분에 있던 코드로 바뀌는 것이다.
화면으로 보면 th:replace를 썼을 때와 안 썼을 때 육안상 바뀐 게 없이 잘 렌더링 될 것이다.
Font-Awesome은 이모티콘같이 생긴 그림을 넣기 쉽게 해주는 글꼴 및 아이콘 툴킷이다.
HTML처럼 class 속성에 정해진 문법대로 단어를 스크립팅하는 방식인 듯하다.
<head>
<link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="/node_modules/font-awesome/css/font-awesome.min.css" />
<script src="/node_modules/jdenticon/dist/jdenticon.min.js"></script>
<!-- <script src="/node_modules/jdenticon/dist/jdenticon.min.js" /> -->
</head>
위 코드처럼 stylesheet인 link
태그는 단일 태그이므로 닫는 태크가 없어도 된다. 하지만 script
는 닫는 태그가 있어야 한다. 그렇지 않으면 script
는 로딩되지 않을 수 있다.
/**
* Returns a copy of this LocalDateTime with the specified number of hours subtracted.
*
* This instance is immutable and unaffected by this method call.
*
* Params : hours - the hours to subtract, may be negative
* Returns : a LocalDateTime based on this date-time with the hours subtracted, not null
* Throws : DateTimeException - if the result exceeds the supported date range
*/
지정된 시간을 뺀 LocalDateTime 값의 복사본을 반환합니다.
이 인스턴스는 변경할 수 없으며 이 메서드 호출의 영향을 받지 않습니다.
파라미터로 뺄 시간을 받는데, 음수일 수 있습니다.
null이 아닌 시간을 뺀 날짜-시간을 기준으로 한 LocalDateTime을 반환합니다.
결과가 지원 날짜 범위를 초과하는 경우 DateTimeException 예외를 던집니다.
프로토타입
public LocalDateTime minusHours(long hours) {
// Arguments 순서 : date, hours, minutes, seconds, nanos, sign
return plusWithOverflow(date, hours, 0, 0, 0, -1);
}
사용 예 : 한 시간마다 인증 메일을 받을 수 있도록 설정할 때
public boolean canSendConfirmEmail() {
/** 이메일의 토큰이 생성된 날짜가 현재 시간에서 한 시간 전인지(그 이상 지났는지) 체크
* 지났으면 true, 아직 안 지났으면 false 반환
*/
return this.emailCheckTokenGeneratedAt.isBefore(LocalDateTime.now().minusHours(1));
}
Reference
JUnit5는 DI를 지원하며 자기가 지원하는 DI 타입이 정해져있다.
의존성을 주입하려고 할 때 JUnit이 먼저 개입한다. 즉, 다른 인스턴스를 넣으려고 시도하기 때문에 @RequiredArgsConstructor
등의 생성자를 통한 의존 주입이 불가하다.
그러므로 @Autowired
를 써서 주입하면 된다.
@SpringBootTest // ExtendWith가 이미 들어있음. 메타 어노테이션 사용됨
class MainControllerTest {
@Autowired
MainService mainService;
...
}
이런 식으로 @Autowired
로 의존주입을 하면 된다.
@BeforeEach
void beforeEach() {
SignUpForm signUpForm = new SignUpForm();
signUpForm.setNickname("brucehan");
signUpForm.setPassword("12345678");
accountService.processNewAccount(signUpForm);
}
Mockito를 이용한 테스트 코드를 작성하다보면 많은 기능(메서드)을 실행하게 되는데, 그중 웹 서비스를 이용하는 프로젝트의 테스트라면 아마 로그인을 통한 테스트도 많이 하게 될 수 있다.
매 테스트마다 계정을 생성하는 로직을 붙이기엔 코드가 길어질 수 있으므로, 이러한 중복을 방지하고자 @BeforeEach
를 이용하여 테스트 계정 생성의 로직 중복을 줄일 수 있다.
다만 매 테스트마다 계정을 생성하려고 하면 DB에 데이터 중복이 일어날 수 있으므로, 한 테스트를 실행할 때마다 깨끗하게 지워줘야 한다.
@AfterEach
void afterEach() {
accountRepository.deleteAll();
}
이런 식으로 테스트를 하고나서 다른 테스트를 실행하기 전에 생성했던 데이터를 지우면 된다.