[Jump to SpringBoot : SBB] JpaRepository 상속 받은 Repository 테스트해보기(+JUnit 프레임워크)

2022. 4. 19. 15:43· 프로젝트/clone coding
목차
  1. JpaRepository 인터페이스
  2. 객체Repository 생성
  3. 리포지터리 테스트 케이스 작성 - 단위 테스트
  4. 데이터 저장하기
  5. 데이터 조회하기
  6. 데이터 수정하기
  7. 데이터 삭제하기

프로젝트 개요 : Jump to SpringBoot 클론코딩 - 회원제 QnA 게시판 웹

프로젝트 환경 : IntelliJ, SpringBoot, JPA, H2

프로젝트 코드 : https://github.com/smkim9202/sbb

 

JpaRepository 인터페이스

기본적인 save(), findById 등의 메서드를 제공해준다.

또한 리포지터리 객체의 메서드가 실행될때 JPA가 해당 메서드명을 분석하여 쿼리를 만들고 실행해준다.

'findBy+엔티티의 속성명'과 같은 리포지터리 메서드를 작성하면 해당 속성의 값으로 데이터를 조회 할 수 있는 쿼리를 만들어주기 때문에 인터페이스에 메서드 선언만하고 구현하지 않고도 실행이 된다.

 

실제로 메서드를 호출 할 때 어떤 쿼리가 실행되는지 콘솔로그로 확인 할 수 있게 설정 할 수 도 있다.

파일명 : 프로젝트명/src/main/resources/application.properties

#JPA
...생략...
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.show_sql=true

 

객체Repository 생성

- 질문(Question) 엔티티의 리포지토리

파일명 : 프로젝트명/src/main/java/패키지명/QusetionRepository.interface

package com.mysite.sbb;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepository extends JpaRepository<Question, Integer> {

}

 

- 답변(Answer) 엔티티의 리포지토리

파일명 : 프로젝트명/src/main/java/패키지명/AnswerRepository.interface

package com.mysite.sbb;

import org.springframework.data.jpa.repository.JpaRepository;

public interface AnswerRepository extends JpaRepository<Answer, Integer> {

}

리포지터리 테스트 케이스 작성 - 단위 테스트

개발한 기능을 실행해서 테스트 하는 방법

  • 자바의 main 메서드 실행
  • 웹 애플리케이션의 컨트롤러를 통해 해당 기능 실행
  • JUnit 프레임워크로 테스트를 실행

=> 위에 두 방법은 준비하하고 실행하는데 오래 걸리고, 반복 실행하기 어렵고, 여러 테스트를 한번에 실행 할 수 없는데 JUnit으로 테스트를 실행하면 이러한 문제들이 해결된다.

 

JUnuit : 테스트코드를 작성하고 작성한 테스트코드를 실행하기 위해 사용하는 자바의 프레임워크

 

테스트 실행시 로컬서버는 중단해야 한다. 만약 로컬서버가 실행 중이라면 오류가 발생한다.

 

테스트 실행시 JUnit 화면이 나타나고 결과가 뜬다 => 초록색이 표시되면 성공 / 빨간색이 표시되면 실패 

 

데이터 저장하기

save : 테이블에 데이터를 저장하는 메서드

- 질문(Question) 엔티티의 리포지토리 테스트

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;


import java.time.LocalDateTime;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest //스프링부트 테스트 클래스임을 의미
class SbbApplicationTests {

	@Autowired
		//객체를 주입하기 위해 사용하는 애너테이션
		//스프링의 DI기능으로 객체를 스프링이 자동으로 생성해준다.
		//객체를 주입하는 방식 3가지 : 필드 주입, setter 주입, 생성자 주입
		//필드 주입은 순환참조 문제 등의 이유로 권장하지 않는다.
		//테스트 코드의 경우 생성자를 통한 객체 주입이 불가능하므로 테스트 코드 작성시에만 사용한다.
	private QuestionRepository questionRepository;


	@Test
		//메서드가 테스트 메서드라고 알려주는 애너테이션
		//JUnit으로 실행하면 @Test 애너테이션이 붙은 메서드가 실행된다.
	void testJpa() {
		//given : q1, q2 객체의 데이터가 주어지고
		Question q1 = new Question();
		q1.setSubject("sbb가 무엇인가요?");
		q1.setContent("sbb에 대해서 알고 싶습니다.");
		q1.setCreateDate(LocalDateTime.now());
        //id는 엔티티 생성 시 설정한대로 데이터 생성시 속성값이 자동으로 1씩 증가

		Question q2 = new Question();
		q2.setSubject("스프링부트 모델 질문입니다.");
		q2.setContent("id는 자동으로 생성되나요?");
		q2.setCreateDate(LocalDateTime.now());

		//when : q1, q2 객체를 save(저장)했을 때
		this.questionRepository.save(q1);  // 첫번째 질문 저장
		this.questionRepository.save(q2);  // 두번째 질문 저장

	}
}

로컬서버 재가동 => H2콘솔 질문테이블 조회 => 저장된 Question 객체의 값이 DB에 저장 되었는지 확인

 

- 답변(Answer) 엔티티의 리포지토리 테스트

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.time.LocalDateTime;
import java.util.Optional;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;

import com.mysite.sbb.answer.Answer;
import com.mysite.sbb.answer.AnswerRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;

	@Autowired
	private AnswerRepository answerRepository;


	@Test
	void testJpa() {
		//given : 질문 id의 값이 2인 데이터에 답변 저장 할 내용이 주어지고
		Optional<Question> oq = this.questionRepository.findById(2);
		assertTrue(oq.isPresent()); //질문 Id속성의 값이 2가 null인지 아닌지 조회
		Question q = oq.get();

		Answer a = new Answer();
		a.setContent("네 자동으로 생성됩니다.");
		a.setQuestion(q);  // 어떤 질문의 답변인지 알기위해서 Question 객체가 필요하다.
		a.setCreateDate(LocalDateTime.now());

		//when : save()로 저장 했을 때
		this.answerRepository.save(a);
		
	}
}

 

데이터 조회하기

findAll : 테이블에 저장된 모든 데이터를 조회하는 메서드

- 질문(Question) 엔티티의 리포지토리 테스트

 

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.List;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest 
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//given : 현재 질문DB에 2개의 질문이 저장되어 있다.
		
		//when : 질문 DB를 findAll(모두조회) 했을 때
		List<Question> all = this.questionRepository.findAll();

		//then : 어떤 값을 원한다
		//assertEquals(기대값, 실제값)
		assertEquals(2, all.size());

		Question q = all.get(0);
		assertEquals("sbb가 무엇인가요?", q.getSubject());
	}
	
}

findById : 테이블에서 id 값으로 데이터 조회하는 메서드

findById의 리턴타입 Question이 아닌 Optional이다.

Optional은 null 처리를 유연하게 처리하기 위해 사용하는 클래스다.isPresent()메서드로 null인지 확인한 후에 get으로 실제 객체값을 얻어야한다.

 

- 질문(Question) 엔티티의 리포지토리 테스트

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.Optional;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest 
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
    
    	//given : 현재 DB에 id컬럼이 1인 subject컬럼의 데이터 값은 'sbb가 무엇인가요?'다.
		//when : 질문 DB에서 id가 1인 데이터를 조회 했을 때
		Optional<Question> oq = this.questionRepository.findById(1);

		//then 
		if (oq.isPresent()) { //oq가 null이 아니라면
			//isPreent() : null인지 아닌지 확인 하는 메서드
			Question q = oq.get(); //null이 아닌것을 확인 후 실제 객체 값을 얻어야 한다.
			assertEquals("sbb가 무엇인가요?", q.getSubject());
		}
	}
}

- 답변(Answer) 엔티티의 리포지토리 테스트 

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Optional;

import com.mysite.sbb.answer.Answer;
import com.mysite.sbb.answer.AnswerRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private AnswerRepository answerRepository;


	@Test
	void testJpa() {
		//when : id속성값이 1인 데이터를 조회 했을 때
		Optional<Answer> oa = this.answerRepository.findById(1);
		assertTrue(oa.isPresent()); //null값이 아니면
		Answer a = oa.get(); 
		
		//then : 질문id가 2를 원한다
		assertEquals(2, a.getQuestion().getId());

	}
}

- 답변(Answer)에 연결된 질문(Question) 찾기 : Answer엔티티의 question 속성 이용하기 - getQuestion()

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.List;
import java.util.Optional;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;

import com.mysite.sbb.answer.Answer;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import org.springframework.transaction.annotation.Transactional;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;

	@Transactional //메서드 종료될 때까지 DB세션을 유지하는 애너테이션
	@Test
	void testJpa() {
		//given : Question Id의 값이 2인 데이터가 주어지고
		Optional<Question> oq = this.questionRepository.findById(2);
		assertTrue(oq.isPresent()); //Id값의 2인 데이터가 null이 아니라면
		Question q = oq.get();

		//when : getAnswerList() 답변리스트를 가져 왔을 때
		List<Answer> answerList = q.getAnswerList();

		//then
		assertEquals(1, answerList.size());
		assertEquals("네 자동으로 생성됩니다.", answerList.get(0).getContent());

	}
}

@Transactional 애너테이션 없이 실행한다면?
org.hibernate.LazyInitializationException 오류 발생
findById() 호출하여 Question 객체 조회 후 DB세션 끊어짐 => DB세션이 종료된 후 실행하는 q.getAnswerList();에서오류 발생한다.
답변데이터 리스트는 q 객체를 조회 할 때 가져오지 않고, q.getAnswerList() 메서드를 호출하는 시점에서 가져오기 때문이다.

필요한 시점에 데이터를 가져오는 방식 : Lazy 방식 / q 객체 조회 시 답변 리스트를 모두 가져오는 방식 : Eager 방식
@OneToMany, @ManyToOne 애너테이션의 옵션으로 fetch=FetchType.LAZY 또는 fetch=FetchType.EAGER 처럼 지정 가능

이 문제는 테스트 코드에서만 발생하는데, 실제 서버에서는 JPA 프로그램 실행 시 DB세션이 종료되지 않기 때문에 LazyInitializationException이 발생하지 않는다.
테스트 코드 수행 시 LazyInitializationException 오류 방지하는 간단한 방법 : @Transactional 애너테이션 사용 - 메서드 종료 될 때까지 DB세션 유지한다.

findBy+엔티티속성명 : 테이블에서 속성명의 값으로 데이터 조회하는 메서드

Id가 아닌 엔티티속성명(컬럼명)들은 메서드를 기본적으로 제공해주지 않는다.

특정 속성명의 값으로 데이터를 조회하고 싶으면 리포지터리를 변경해야한다.=> '객체타입 findBy+속성명(속성명타입 속성명);'를 추가해주자단, 중복된 값(속성값이 똑같은 경우)이 있을 시 테스트가 실패한다.

 

- 질문(Question) 엔티티의 리포지토리 테스트 - findBySubject()

파일명 : 프로젝트명/src/main/java/패키지명/QusetionRepository.java

package com.mysite.sbb;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepository extends JpaRepository<Question, Integer> {

	Question findBySubject(String subject);
    	//findBySbject() : 제목으로 테이블 데이터 조회하기

}

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//when : findBySubject()로 제목이 "sbb가 무엇인가요?"인 테이블 데이터를 조회 했을 때
		Question q = this.questionRepository.findBySubject("sbb가 무엇인가요?");
		
		//then
		assertEquals(1, q.getId());
	}
}

findBy+엔티티속성명1And엔티티속성명2 : 두 개의 속성을 And 조건으로 조회하는 메서드

쿼리문의 where 조건을 결정하는 역할을 한다. 여러 컬럼을 And로 검색

 

- 질문(Question) 엔티티의 리포지토리 테스트 - findBySubjectAndContent()

파일명 : 프로젝트명/src/main/java/패키지명/QusetionRepository.java

package com.mysite.sbb;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepository extends JpaRepository<Question, Integer> {

	...생략...
    Question findBySubjectAndContent(String subject, String content);
    	//findBySubjectAndContent() : 제목과 내용을 함께 조회

}

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//when : findBySubjectAndContent()로 제목과 내용을 함께 조회하면
		Question q = this.questionRepository.findBySubjectAndContent(
				"sbb가 무엇인가요?", "sbb에 대해서 알고 싶습니다.");
		//then
		assertEquals(1, q.getId());
	}
}

And외에 where 조건을 결정하는 항목들

항목 예제 설명
And findBySubjectAndContent(String subject, String content) 여러 컬럼을 and 로 검색
Or findBySubjectOrContent(String subject, String content) 여러 컬럼을 or 로 검색
Between findByCreateDateBetween(LocalDateTime fromDate, LocalDateTime toDate) 컬럼을 between으로 검색
LessThan findByIdLessThan(Integer id) 작은 항목 검색
GreaterThanEqual findByIdGraterThanEqual(Integer id) 크거나 같은 항목 검색
Like findBySubjectLike(String subject) like 검색
In findBySubjectIn(String[] subjects) 여러 값중에 하나인 항목 검색
OrderBy findBySubjectOrderByCreateDateAsc(String subject) 검색 결과를 정렬하여 전달

응답 결과가 여러건인 경우에는 리포지터리 메서드의 리턴 타입을 엔티티명이 아닌 List<엔티티명>으로 해야한다.

 

쿼리 생성 규칙 공식문서 

https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation

 

Spring Data JPA - Reference Documentation

Example 109. Using @Transactional at query methods @Transactional(readOnly = true) interface UserRepository extends JpaRepository { List findByLastname(String lastname); @Modifying @Transactional @Query("delete from User u where u.active = false") void del

docs.spring.io

findBy+엔티티속성명Like : 속성명에 특정문자열이 포함되어 있는 데이터 조회하는 메서드

Like : 특정문자열 포함되어 있는 데이터 조회

  • 문자열% : "문자열"로 시작하는 문자열
  • %문자열 : "문자열"로 끝나는 문자열
  • %문자열% : "문자열"을 포함하는 문자열

- 질문(Question) 엔티티의 리포지토리 테스트 - findBySubjectAndContent()

파일명 : 프로젝트명/src/main/java/패키지명/QusetionRepository.java

package com.mysite.sbb;

import org.springframework.data.jpa.repository.JpaRepository;

public interface QuestionRepository extends JpaRepository<Question, Integer> {

	...생략...
    List<Question> findBySubjectLike(String subject);
    	//findBySubjectLike() : 제목에 특정문자열이 포함되어 있는 데이터 조회

}

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.List;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//when : findBySubjectLike("sbb%")로 제목이 sbb로 시작하는 데이터 조회 할 때
		List<Question> qList = this.questionRepository.findBySubjectLike("sbb%");
		
		//then
		Question q = qList.get(0);
		assertEquals("sbb가 무엇인가요?", q.getSubject());
	}
}

 

 

 

데이터 수정하기

update문이 실행된다.

save

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Optional;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//given : Id가 1인 데이터가 주어졌을 때 수정된 값이 주어지고
		Optional<Question> oq = this.questionRepository.findById(1);
		assertTrue(oq.isPresent()); //Id값의 null이 아니면
		Question q = oq.get(); 
		q.setSubject("수정된 제목"); //제목을 수정해준 값을
		
		//when : save()로 저장했을 때
		this.questionRepository.save(q);
	}
}

 

데이터 삭제하기

delete

파일명 : 프로젝트명/src/test/java/패키지명/프로젝트명ApplicationTests.java

package com.mysite.sbb;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.Optional;

import com.mysite.sbb.Question.Question;
import com.mysite.sbb.Question.QuestionRepository;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;


@SpringBootTest
class SbbApplicationTests {

	@Autowired
	private QuestionRepository questionRepository;


	@Test
	void testJpa() {
		//given : Id속성의 값이 1인 데이터 객체가 주이지고
		assertEquals(2, this.questionRepository.count());
			//리포지터리의 count() : 해당 리포지터리의 총 데이터건수 리턴
		Optional<Question> oq = this.questionRepository.findById(1);
		assertTrue(oq.isPresent()); //Id값이 1인 데이터가 null인지 아닌지 조회
		Question q = oq.get(); 

		//when : delete로 q객체를 삭제 했을 때
		this.questionRepository.delete(q);

		//then 
		assertEquals(1, this.questionRepository.count());
	}
}

 

 

'프로젝트 > clone coding' 카테고리의 다른 글

[Jump to SpringBoot : SBB] 스프링부트 windows cmd창으로 빌드하고 실행  (0) 2022.04.21
[Jump to SpringBoot : SBB] 서비스와 DTO  (0) 2022.04.20
[Jump to SpringBoot : SBB] thymeleaf 템플릿 엔진(+ROOT URL)  (0) 2022.04.19
[Jump to SpringBoot : SBB] SpringBoot 기본 요소(Controller, JPA, Entity, Repository)  (0) 2022.04.19
[Jump to SpringBoot : SBB] IntelliJ에서 SpringBoot 사용하기  (0) 2022.04.18
  1. JpaRepository 인터페이스
  2. 객체Repository 생성
  3. 리포지터리 테스트 케이스 작성 - 단위 테스트
  4. 데이터 저장하기
  5. 데이터 조회하기
  6. 데이터 수정하기
  7. 데이터 삭제하기
'프로젝트/clone coding' 카테고리의 다른 글
  • [Jump to SpringBoot : SBB] 서비스와 DTO
  • [Jump to SpringBoot : SBB] thymeleaf 템플릿 엔진(+ROOT URL)
  • [Jump to SpringBoot : SBB] SpringBoot 기본 요소(Controller, JPA, Entity, Repository)
  • [Jump to SpringBoot : SBB] IntelliJ에서 SpringBoot 사용하기
개발원슝이
개발원슝이
꾸준히 개발공부를 합니다.
개발원슝이
꾸준히 개발슝이
개발원슝이
전체
오늘
어제
  • ALL (240) N
    • 프로젝트 (34)
      • clone coding (19)
      • mini project (5)
      • Team project(with KIC) (10)
    • 문제 (37)
      • 백준 (7)
      • 프로그래머스 (14)
      • 정보처리기사실기 (16)
    • 설치 (9)
    • 개발 기초 (13)
    • 프로그래밍언어 (122) N
      • HTML (16)
      • CSS (17)
      • JavaScript (20) N
      • JAVA (13)
      • JSP (10)
      • Python (22)
      • C언어 (24)
    • 프레임워크 (6)
      • Spring (3)
      • Django (3)
    • DB (2)
      • MySQL (2)
    • AWS (1)
    • 오류 (2)
    • 이것저것 (6)
    • 전공자 개발 (3) N
    • 비전공자 개발 (5)

블로그 메뉴

  • 네이버블로그(강의노트)
  • GitHub
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 따배씨
  • 파이썬공부
  • 점프 투 파이썬
  • 홍정모교수님
  • 홍정모의 따라하며 배우는 C언어
  • 백준
  • javascript
  • 인프런
  • 코딩테스트
  • 생활코딩

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
개발원슝이
[Jump to SpringBoot : SBB] JpaRepository 상속 받은 Repository 테스트해보기(+JUnit 프레임워크)
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.