이 포스팅의 코드 및 정보들은 강의를 들으며 정리한 내용을 토대로 작성한 것이 일부 존재합니다.

1. Thymeleaf fragment 활용하기

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를 썼을 때와 안 썼을 때 육안상 바뀐 게 없이 잘 렌더링 될 것이다.

2. Font-Awesome 토막 상식

Font-Awesome은 이모티콘같이 생긴 그림을 넣기 쉽게 해주는 글꼴 및 아이콘 툴킷이다.
HTML처럼 class 속성에 정해진 문법대로 단어를 스크립팅하는 방식인 듯하다.

  • fa : Font-Awesome을 사용하겠다는 것

3. 헤더에서는 link와 script의 닫는 태그 차이

<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는 로딩되지 않을 수 있다.

4. Spring에서 한 시간마다 뭔가 체크하고 싶을 때

    /**
     * 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

5. JUnit5에서의 의존성 주입

JUnit5는 DI를 지원하며 자기가 지원하는 DI 타입이 정해져있다.

의존성을 주입하려고 할 때 JUnit이 먼저 개입한다. 즉, 다른 인스턴스를 넣으려고 시도하기 때문에 @RequiredArgsConstructor 등의 생성자를 통한 의존 주입이 불가하다.
그러므로 @Autowired를 써서 주입하면 된다.

@SpringBootTest // ExtendWith가 이미 들어있음. 메타 어노테이션 사용됨
class MainControllerTest {

    @Autowired
    MainService mainService;
    ...
}

이런 식으로 @Autowired로 의존주입을 하면 된다.

6. @BeforeEach, @AfterEach 토막 팁(feat.Mockito)

@BeforeEach
void beforeEach() {
    SignUpForm signUpForm = new SignUpForm();
    signUpForm.setNickname("brucehan");
    signUpForm.setPassword("12345678");
    accountService.processNewAccount(signUpForm);
}

Mockito를 이용한 테스트 코드를 작성하다보면 많은 기능(메서드)을 실행하게 되는데, 그중 웹 서비스를 이용하는 프로젝트의 테스트라면 아마 로그인을 통한 테스트도 많이 하게 될 수 있다.

매 테스트마다 계정을 생성하는 로직을 붙이기엔 코드가 길어질 수 있으므로, 이러한 중복을 방지하고자 @BeforeEach를 이용하여 테스트 계정 생성의 로직 중복을 줄일 수 있다.

다만 매 테스트마다 계정을 생성하려고 하면 DB에 데이터 중복이 일어날 수 있으므로, 한 테스트를 실행할 때마다 깨끗하게 지워줘야 한다.

@AfterEach
void afterEach() {
    accountRepository.deleteAll();
}

이런 식으로 테스트를 하고나서 다른 테스트를 실행하기 전에 생성했던 데이터를 지우면 된다.

전체 Reference

profile
만 가지 발차기를 한 번씩 연습하는 사람은 두렵지 않다. 내가 두려워 하는 사람은 한 가지 발차기를 만 번씩 연습하는 사람이다. - Bruce Lee

0개의 댓글