JUnit 4 테스트 작성 (1) - 테스트에 필요한 객체 생성

gentledot·2021년 3월 28일
0

테스트와 로깅

목록 보기
2/5

참고자료

개요

  • 테스트 환경에서 단위테스트를 구현하는 방식에 대해 정리하고자 포스트를 작성하였습니다.
  • 정보를 찾아 테스트를 작성하였지만 작성된 단위테스트에 대한 피드백을 받을 수 없는 환경이기 때문에 부정확한 정보가 정리되었을 수 있습니다.
  • 테스트 환경은 이전 포스트에 정리하였습니다.

    잘못된 내용이나 더 나은 방식 등에 대한 의견은 댓글로 피드백 부탁드리겠습니다. :)

Test 작성에 필요한 객체들

Test-Context 설정

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 org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:framework/spring/context-*.xml",
        "file:src/main/webapp/WEB-INF/config/framework/springmvc/dispatcher-servlet.xml"})
@WebAppConfiguration("file:src/main/webapp")
public class MainTest {
		@Autowired
    public WebApplicationContext wac;
}
  • servlet 설정 및 context 설정을 @ContextConfiguration annotation으로 설정합니다.
    • classpath:framework/spring-test/context-*.xml
      테스트 context 설정 폴더
      • classpath 탐색 시 우선 현재 폴더 위치(test)의 해당 context 설정 파일을 탐색, 그 다음에 main 폴더를 탐색한다.
    • dispatcher-servlet은 기존 main 폴더의 파일을 참조하도록 설정하였습니다.
      • Spring에서 default location은 file:src/main/webapp 이라고 합니다.
      • default가 아닌 다른 경로는 file:xx 구문을 사용합니다.
      @WebAppConfiguration("file:src/webapp")

필요한 설정을 담은 Test 객체 생성

  • login 정보에 대한 처리를 session으로 확인하고 있기 때문에 spring-context 구성 및 session을 임의로 구성하고자 하였습니다.
    • 임의로 만들 session은 MockHttpSession 객체로 추가하였습니다.
  • 테스트를 작성할 때마다 해당 정보를 입력하는 것이 반복될 것이기 때문에 MainTest라는 객체를 생성하고 이를 상속하는 방식으로 테스트를 작성하고자 하였습니다.

MainTest.java


import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.context.WebApplicationContext;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:framework/spring-test/context-*.xml",
        "file:src/main/webapp/WEB-INF/config/framework/springmvc/dispatcher-servlet.xml"})
@WebAppConfiguration
public class MainTest {

    @Autowired
    public WebApplicationContext wac;

    public MockHttpSession mockSession;

    public MainTest() {
        /* testSession : 
        id = user304 login 후 생성되는 session */
        SessionVO session = new SessionVO();
        session.setUser_id("user304");
        session.setCompany_id("testId");
        session.setNm_company("(테스트회사");
        session.setNm_user("테스터1");
        
        ...

        mockSession = new MockHttpSession();
        mockSession.setAttribute("sessionVO", session);
    }
}
  • SessionVO : session 정보를 담기 위한 vo 입니다.
    • 로직 상에서 session이 필요한 경우 mockSession.getAttribute("sessionVO"); 로 꺼내쓰고
    • 테스트와 무관하다면 stubbing을 통해 (mockito 활용) 임의의 값으로 설정하여 테스트를 작성하고 있습니다.

MainTest.java 개선

@Ignore("테스트 설정 클래스")
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:framework/spring-test/context-*.xml",
        "file:src/main/webapp/WEB-INF/config/framework/springmvc/dispatcher-servlet.xml"})
@WebAppConfiguration
public class MainTest {
    public static final Logger LOGGER = LoggerFactory.getLogger(MainTest.class);
    public MockHttpSession mockSession;

    private TestSessions testSessions = new TestSessions();

    public MainTest() {
        /* testSession :
        id = user304 login 후 생성되는 session */
        SessionVO session = testSessions.setTestSessionUser304();

        mockSession = new MockHttpSession();
        mockSession.setAttribute("sessionVO", session);
    }

    public MainTest(String userId) {
        /* testSession :
        login 되는 user_id에 따라 생성되는 session이 다름 */
        SessionVO session = testSessions.setTestSessionUser304();

        if ("testUser1".equals(userId)) {
            session = testSessions.setTestSessionTestUser1();
        } else if ("testUser2".equals(userId)) {
            session = testSessions.setTestSessionTestUser2();
        }

        mockSession = new MockHttpSession();
        mockSession.setAttribute("sessionVO", session);
    }

    @After
    public void clearSession() {
        mockSession.clearAttributes();
        mockSession = null;
    }
}
  • session의 경우 다른 테스트 계정의 사용도 고려하여 TestSessions 클래스를 생성하여 세션 생성 기능을 관리
    • 생성자의 param에 테스트 계정 id를 입력하는 경우 입력한 id의 세션이 생성되도록 구성
    • 만약 테스트 계정이 추가로 구성되어야 한다면 setTestSession() method를 정비해야 할 것으로 생각됩니다.

TestSessions.java

/*
 * 테스트를 위한 세션 설정을 위한 클래스
 * */
public class TestSessions {

    public TestSessions() {
    }

    /* user304 로그인 시 생성되는 세션 */
    public SessionVO setTestSessionUser304() {
        SessionVO session = new SessionVO();

        ...
        
        session.setNm_company(테스터304");
        session.setActno("123-45-67890");
        
        ...
        
        return session;
    }

    /* testUser1 로그인 시 생성되는 세션 (영리 회계 확인 등) */
    public SessionVO setTestSessionTestUser1() {
        SessionVO session = new SessionVO();
        
        ...

        session.setNm_company("테스트님1");
        session.setActno("123-45-67890");
        
        ...

        return session;
    }

    /* testUser2 로그인 시 생성되는 세션 (비영리 회계 확인, 기능 점검 등) */
    public SessionVO setTestSessionTestUser2() {
        SessionVO session = new SessionVO();

        ...

        session.setNm_company("테스트님2");
        session.setActno("999-99-99999");
        
        ...
        
        return session;
    }
}
  • 테스트의 성격에 따라 다른 테스트 계정이 사용되게 되어 필요한 테스트계정의 세션을 설정하는 부분에서 관리가 용이하도록 새로운 객체를 생성하였습니다.

MainMvcTest.java

package kr.co.ehm.init;

import org.junit.Before;
import org.junit.Ignore;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

@Ignore("테스트 설정 클래스")
public class MainMvcTest extends MainTest {

    @Autowired
    public WebApplicationContext wac;

    public MockMvc mockMvc;

    public MainMvcTest() {
    }

    public MainMvcTest(String userId) {
        super(userId);
    }

    @Before
    public void setUp() {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }
}
  • MockMvc 생성을 담당하는 객체를 따로 구성하도록 변경.
    • 공통으로 설정되어야 하는 세션 설정 등이 구성되는 MainTest를 상속하여 구성
  • MVC 테스트는 MainMvcTest를 상속하여 설정하고 로직 확인을 위한 단위테스트는 MainTest를 상속하여 설정하는 방식으로 구현하였습니다.

테스트 설명을 적을 Annotation 생성

  • JUnit 4에서는 테스트 실행 시 실행된 method 명으로 테스트 내용을 구분할 수 밖에 없습니다.
  • JUnit 5의 @DisplayName("A special test case") 와 같은 방식을 참조항려 @value에 String을 입력할 수 있는 annotation을 생성하여 테스트에 대한 구분이 용이하도록 설명을 달아보고자 하였습니다.
    • 해당 아이디어는 백기선님의 인프런 강의 (참고자료 링크 참조)에서 소개된 내용을 활용하였습니다.

@TestDesc() 생성

import org.junit.Ignore;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Ignore
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface TestDesc {
    String value();
}
  • test 폴더 전체를 실행할 때 테스트할 대상이 아니므로 @Ignore 를 붙였습니다. (테스트로 실행되지 않음.)
  • @Target 으로 method에 적용하는 annotation으로 설정하였습니다.
  • @Retention 으로 컴파일 단계에서 사용되지 않도록 설정하였습니다. (즉, 실행되지 않는 구문이 되므로 주석처럼 쓸 수 있습니다.)
  • @interface type으로 해당 객체가 @annotation 임을 설정하였습니다.
  • 이렇게 설정한 annotation은 테스트 작성 시 다음과 같이 활용하였습니다.
    @Test
    @TestDesc("전표 저장 테스트 (일반대체전표, 구분 : 출금)")
    @Transactional
    public void saveAccountingBookWithWithdrawalGeneralSlip() throws Exception {
           ...
    }
profile
그동안 마신 커피와 개발 지식, 경험을 기록하는 공간

0개의 댓글