-
인수 테스트 코드 리팩터링-1Today I Learned 2023. 1. 3. 21:13
인수 테스트 코드를 수정하는 과정에서 사용한 것들을 정리했다.
CodeceptJS에서 className으로 요소 확인하기
인수 테스트에서 class 속성을 갖는 요소의 화면 존재 여부를 다음과 같이 확인할 수 있다.
// src/components/post/PostGameMembers.jsx <button className="member"> // elements </button>
// tests/registration_acceptance_test.js I.seeElement('.member');
CodeceptJS에서 입력 필드 값을 비우면서, 입력 필드 상태에도 반영시키기
게시글 작성 기능 중, 필수 입력 폼에 내용을 입력하지 않고 게시글 작성을 시도하는 경우 예외를 발생시키는 동작의 인수 테스트를 다음과 같이 수행하려고 했다.
- 모든 입력 폼에 내용을 입력한다.
- 특정 입력 폼의 내용을 비운다.
- '작성하기' 버튼을 누른다.
- 내용을 입력해달라는 예외 메시지를 확인한다.
특정 입력 폼에만 내용이 입력되지 않은 경우를 만드는 방법에는 두 가지가 있었는데, 특정 입력 폼을 제외한 모든 입력 폼에 내용을 입력하게 하는 방법과, 모든 입력 폼에 내용을 입력한 뒤 특정 입력 폼의 내용만 비우는 방법이 있었다. 후자의 방법은 setps_file.js에 모든 입력 폼에 내용을 입력하는 로직을 메서드화할 수 있었기 때문에 재사용을 통해 코드 중복을 줄일 수 있어 후자의 방법을 선택했다.
처음에는 입력 폼의 내용을 지우는 것을 다음과 같이 시도했다.
// tests/writing_post_test.js // 다음의 두 가지 방법으로 시도했다. I.clearField('Label') I.fillField('Label', '')
이렇게 테스트를 수행했을 때는 화면 상에서는 입력 필드가 지워지는 것이 확인되었지만, 인수 테스트에서 예외를 처리하지 않고 기존에 입력했었던 내용으로 게시글을 등록하는 문제가 발생했다. 디버깅을 수행한 결과, 입력 필드의 상태를 관리하고 있는 PostFormStore에 지워진 입력 필드의 상태가 반영되지 않는 것을 확인했다.
문제 해결을 위해 웹에서 정보를 찾던 중 화면을 클릭하거나 키보드의 버튼을 누르는 것과 같은 동작을 CodeceptJS에서 수행할 수 있음을 확인하고 소스코드에 적용했다. 입력 필드를 마우스 클릭으로 직접 선택한 뒤, 입력 값들을 전체 선택하고 직접 지우는 방식의 테스트 코드를 작성해 문제를 해결했다.
// steps_file.js const backdoorBaseUrl = 'http://localhost:8000/backdoor'; module.exports = function () { return actor({ setupWritingPostCase() { this.amOnPage(`${backdoorBaseUrl}/setup-writing-post-case`); }, login({ username, password }) { // ... }, fillPostForm() { // ... } clearInputField(locator) { this.doubleClick(locator); this.pressKey(['Shift', 'Home']); this.pressKey('Backspace'); }, }); };
// tests/writing_post_test.js Feature('4. 운동 모집 게시글 작성: ' + '운동 팀원을 모집하는 사람이 ' + '자신의 게시글을 운동을 찾는 사람들에게 노출시키기 위해 ' + '운동 팀원을 모집하는 게시글을 작성할 수 있다.'); Before(({ I }) => { I.clearDatabases(); }); Scenario('종목을 입력하지 않은 경우', ({ I }) => { // Given I.setupWritingPostCase(); I.login({ username: 'user1234', password: 'Password!1', }); // When I.amOnPage('/write'); I.fillPostForm(); I.clearInputField('#input-game-exercise'); I.click('작성하기'); // Then I.seeElement('[placeholder="종목을 입력하지 않았습니다."]'); });
References
- https://github.com/codeceptjs/CodeceptJS/issues/499
CodeceptJS에서 체크박스 관련 동작 수행하기
CodeceptJS에서 체크박스를 클릭하고, 체크박스가 클릭되거나 클릭되지 않았는지 다음과 같이 검증할 수 있다.
// src/components/notices/NoticeTitle.jsx <Checkbox type="checkbox" id="1" />
// tests/notice_test.js I.checkOption('[id="1"]'); I.seeCheckboxIsChecked('[id="1"]');
References
- https://github.com/codeceptjs/CodeceptJS/issues/877
JavaScript에서 Date 객체를 toISOString()으로 변환할 때 한국 시간을 기준으로 변환하기
게시글을 등록한 뒤 등록된 게시글의 내용을 인수 테스트로 검증하는 과정에서 입력했던 운동 예정 날짜와 다른 날짜가 운동 예정 날짜로 등록되어 있는 문제를 확인했다. 디버깅을 진행한 결과, 게시글 작성 과정에서 입력한 시간과 서버에서 DTO로 전달받은 시간 값이 다르다는 점이 확인되었다.
사용자가 입력한 날짜 값은 서버에 전달되기 전에 Date 객체를 문자열 형태로 변환하기 위해 .toISOString() 메서드를 이용해 문자열로 변환하고 있었다. 문제는 이처럼 Date 객체를 단순화한 확장 ISO 형식인 ISO 8601으로 변환할 경우, UTC Timezone 기준으로 변환되기 때문에 UTC+9인 한국 시간보다 9시간 이전의 시간 값으로 변환되는 문제가 있었다.
문제 해결을 위해 Date 객체에 9시간만큼의 Offset을 더해준 뒤에 ISO 8601 형태로 변환하도록 하는 식으로 문제를 해결했다.
const dateOffset = 1000 * 60 * 60 * 9; const date = (new Date(this.gameDate.getTime() + dateOffset)).toISOString();
References
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString
- https://archijude.tistory.com/560?category=826157
JPA로 List를 가져올 때 정렬된 상태로 가져오기
// services/GetNoticesService.java public NoticesDto findAllNoticesOfUser(Long currentUserId) { List<Notice> notices = noticeRepository.findAllByUserId( currentUserId, Sort.by(Sort.Direction.DESC, "createdAt")); List<NoticeDto> noticeDtos = notices.stream() .filter(Notice::active) .map(Notice::toDto) .toList(); return new NoticesDto(noticeDtos); }
// repositories/NoticeRepository.java public interface NoticeRepository extends JpaRepository<Notice, Long> { List<Notice> findAllByUserId(Long userId, Sort sort); }
References
- https://lovemewithoutall.github.io/it/spring-data-sort/
'Today I Learned' 카테고리의 다른 글
2023년 1월 6일 (0) 2023.01.06 2023년 1월 5일 (0) 2023.01.05 CodeceptJS에서 로그인하지 않고 특정 페이지에 접속하는 경우 인가 정보를 가져오지 못하는 문제 해결 과정 (0) 2023.01.02 Parcel로 React 프로젝트 빌드 후 실행 시 src 디렉터리를 참조하지 못하는 문제 해결 과정 (0) 2023.01.02 WebSocket을 이용한 실시간 채팅 구현하기 2: 클라이언트 (0) 2022.12.21