2022_02_26 - oneso123456789/2022 GitHub Wiki

other

9.1.1 스프링의 서비스 객체 설정(root-context.xml)

비즈니스 계층의 인터페이스와 구현 클래스가 작성되었다면,
이를 스프링의 빈으로 인식하기 위해서 roo-context.xml에
@Service어노테이션이 있는 com.crow.service 패키지를 스캔
하도록 추가해야함

프로젝트 생성 시 만들어진 root-context.xml의 네임스페이스
탭에서 context 항목을 추가함

네임스페이스를 추가하면 해당 이름으로 시작하는 태그들을 활용할
수 있음

root-context.xml의 일부

    <context:component-scan
        base-package="com.crow.service" />

9.2 비즈니스 계층의 구현과 테스트

BoardMapper와 BoardService, BoardServiceImpl에 대한
구조설정이 완료되었으므로 'src/test/java' 밑에
com.crow.service.BoardServiceTests 클래스를 작성해서 진행함

테스트 환경의 BoardServiceTests 클래스

package com.crow.service;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardServiceTests {
    
    @Setter(onMethod_ = {@Autowired})
    private BoardService service;
    
    @Test
    public void testExist() {
        
        log.info(service);
        assertNotNull(service);
        log.info("여기가 로그 끝");
    }
    
}

BoardServiceTests의 첫 테스트는 BoardService 객체가 제대로 주입이 가능한지 확인하는 작업으로 시작함
정상적으로 BoardService 객체가 생성되고 BoardMapper가 주입되었다면
아래와 같이 Service 객체와 데이터베이스 관련 로그가 출력됨

9.2.1 등록 작업의 구현과 테스트

등록 작업은 BoardServiceImpl에서 파라미터로 저날되는 BoardVO 타입의 객체를
BoardMapper를 통해서 처리함
구현되는 코드는 다음과 같음

BoardServiceImpl 클래스의 일부

    @Override
    public void register(BoardVO board) {
        // TODO Auto-generated method stub
        
        log.info("register......" + board);
        
        mapper.insertSelectKey(board);

    }

BoardService는 void 타입으로 설계되었으므로 mapper.insertSelectKey()
의 반환값인 int를 사용하지 않고 있지만, 필요하다면 예외처리나 void
대신에 int 타입을 이용해서 사용할 수도 있음

mapper의 insertSelectKey()를 이용해서 나중에 생성된 게시물의 번호를
확인할 수 있게 작성함 이에 대한 테스트는 아래와 같이 작성함

BoardServiceTests 클래스의 일부

    @Test
    public void testRegister() {

        BoardVO board = new BoardVO();
        board.setTitle("서비스 테스트 작성제목");
        board.setContent("서비스 테스트 작성내용");
        board.setWriter("서비스 테스트 작성자");

        service.register(board);

        log.info("생성된 게시물의 번호: " + board.getBno());
    }

testRegister()의 테스트 결과는 다음과 같이 생성된 게시물의 번호를
확인할 수 있음.

9.2.2 목록(리스트) 작업의 구현과 테스트

BoardServiceImpl 클래스에서 현재 테이블에 저장된 모든 데이터를 가져오는
getList()는 아래와 같이 구현됨

BoardServiceImpl 클래스의 일부

    @Override
    public List<BoardVO> getList() {
        // TODO Auto-generated method stub
        
        log.info("getList......");
        
        return mapper.getList();
    }

테스트 코드는 아래와 같이 작성할수있음

com.crow.service.BoardServiceTests 클래스의 일부

    @Test
    public void testGetList() {

        service.getList().forEach(board -> log.info(board));
    }

테스트의 실행 결과로 등록 작업을 테스트할 때 추가된 데이터가 정상적으로
나오는지 확인바람

9.2.3 조회 작업의 구현과 테스트

조회는 게시물의 번호가 파라미터이고 BoardVO의 인스턴스가 리턴됨

BoardServiceImpl 클래스의 일부

    @Override
    public BoardVO get(Long bno) {
        // TODO Auto-generated method stub

        log.info("get......" + bno);

        return mapper.read(bno);
    }

com.crow.service.BoardServiceTests 클래스의 일부

    @Test
    public void testGet() {

        log.info(service.get(1L));
    }

9.2.4 삭제/수정 구현과 테스트

삭제/수정은 메서드의 리턴 타입을 void로 설계할 수도 있지만 엄격하게
처리하기 위해서 Boolean 타입으로 처리함

com.crow.service.BoardServiceImpl 클래스의 일부

    @Override
    public boolean modify(BoardVO board) {
        // TODO Auto-generated method stub
        log.info("modify......" + board);

        return mapper.update(board) == 1;
    }

    @Override
    public boolean remove(Long bno) {
        // TODO Auto-generated method stub

        log.info("remove......" + bno);

        return mapper.delete(bno) == 1;
    }

정상적으로 수정과 삭제가 이루어지면 1이라는 값이 반환되기 때문에
'==' 연산자를 이용해서 true/false를 처리할 수 있음

테스트 코드는 다음과 같이 작성함

com.crow.BoardServiceTests 클래스의 일부

    @Test
    public void testDelete() {
        
        // 게시물 번호의 존재 여부를 확인하고 테스트 할 것
        log.info("REMOVE RESULT: " + service.remove(2L));
        
    }
    
    @Test
    public void testUpdate() {
        
        BoardVO board = service.get(1L);
        
        // 입력한 번호의 내용이 존재 하지 않으면 리턴을 시킴
        if(board == null) {
            return ;
        }
        
        board.setTitle("서비스 테스트중 제목 수정합니다");
        log.info("MODIFY RESULT: " + service.modify(board));
    }

testDelete()의 경우에는 해당 게시물이 존재할 때 true를 반환하는 것을
확인할수 있고,
testUpdate()의 경우에는 특정한 게시물을 먼저 조회하고, title 값을 수정한 후 이를 업데이트함

Chapter 10 프레젠테이션(웹)계층의 CRUD 구현

비즈니스 계층의 구현까지 모든 테스트가 진행되었다면 이제 남은 작업은
프레젠테이션 계층인 웹 구현임
웹은 이전 PART 2에서 실습한 내용을 기준으로 현재 프로젝트에 반영해야함

10.1 Controller의 작성

스프링 MVC의 Controller는 하나의 클래스 내에서 여러 메서드를 작성하고,
@RequestMapping등을 이용해서 URL을 분기하는 구조로 작성할 수 있기 때문에
하나의 클래스에서 필요한 만큼 메서드의 분기를 이용하는 구조로 작성함

과거에는 이 단계에서 Tomcat(WAS)을 실행하고 웹 화면을 만들어서 결과를
확인하는 방식의 코드를 작성해 왔음
이 방식은 시간도 오래 걸리거니와 테스트를 자동화 하기에 어려움이 많음

따라서 이 단계에서는 WAS를 실행하지 않고 Controller를 테스트 할 수 있는
방법을 학습함

BoardController의 분석

작성하기 전에는 반드시 현재 원하는 기능을 호출하는 방식에 대해 다음과 같이
테이블로 정리한 후 코드를 작성하는 것이 좋음 BoardController분석
테이블에서 From 항목은 URL을 호출하기 위해서 별도의 입력화면이 필요하다는 것을 의미함
이에 대한 설계는 화면을 구성하는 단계에서 진행할 수 있음

⚠️ **GitHub.com Fallback** ⚠️