[AXBoot] 단위 테스트 코드 작성 / Spring Framework와 AXBoot

yesjm·2021년 4월 22일
0

어제에 이어서 테스트 코드를 작성해본다.
어제 saveByQueryDsl의 단위테스트를 만들어보라는 숙제를 받았지만 해결 못했당,,

오전 수업

단위 테스트

saveByQueryDsl

CompanyService.java
제대로 결과가 반영된건지 확인하기 위해 return 값을 반환했다.

    @Transactional
    public int saveByQueryDsl(List<Company> requests) {
        int result = 0;
        for (Company company: requests) {
            if (company.isCreated()) {
                save(company);
                result = 1;
            } else if (company.isModified()) {
                update(qCompany)
                        .set(qCompany.companyNm, company.getCompanyNm())
                        .set(qCompany.ceo, company.getCeo())
                        .set(qCompany.bizno, company.getBizno())
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
                result = 1;

            } else if (company.isDeleted()) {
                delete(qCompany)
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
                result = 1;
            }
        }
        return result;
    }

CompanyServiceTest.java

    @Test
    public void testSaveByQueryDsl_create(){
        //given
        List<Company> requests = new ArrayList<Company>();
        Company company = new Company();
        company.setCompanyNm("당근마켓");
        company.setCeo("당근");
        company.setBizno("543221");
        company.set__created__(true);

        requests.add(company);
        //when
        int result = this.companyService.saveByQueryDsl(requests);

        //then
        assertTrue(result == 1);
    }

데이터가 잘 들어간 것을 볼 수 있다.

swagger에서 확인했을 때도 마찬가지!

어제는 ArrayList를 안만들고 계속 해결하려고 했던 바보,, 자바 문법을 다 잊은건지,,, 공부를 다시 해야겠다,,
가장 핵심은 company.set__created__(true);

update 기능 확인도 마찬가지로 작성

    @Test
    public void testSaveByQueryDsl_update(){
        //given
        List<Company> requests = new ArrayList<Company>();
        Company company = new Company();
        company.setId(161L);
        company.setCompanyNm("당근마켓");
        company.setCeo("김용현");
        company.setBizno("543221");
        company.set__modified__(true);
        requests.add(company);

        //when
        int result = this.companyService.saveByQueryDsl(requests);

        //then
        assertTrue(result == 1);
    }

delete 기능

    @Test
    public void testSaveByQueryDsl_delete(){
        //given
        List<Company> requests = new ArrayList<Company>();
        Company company = new Company();
        company.setId(162L);
        company.set__deleted__(true);
        requests.add(company);

        //when
        int result = this.companyService.saveByQueryDsl(requests);

        //then
        assertTrue(result == 1);
    }

테스트 시에 id값을 모르기 때문에 id값을 확인하기 위한 동작을 계속해야한다. 이걸 해결하기 위해 id값을 리턴해보자.
CompanyService.java

    @Transactional
    public Long saveByQueryDsl(List<Company> requests) {
        Long result = 0L;
        for (Company company: requests) {
            if (company.isCreated()) { 
                Company rtnObj = save(company); //결과 자체를 받겠다.
                result = rtnObj.getId(); //받아온 결과의 ID를 리턴.
            } else if (company.isModified()) {
                result = update(qCompany)
                        .set(qCompany.companyNm, company.getCompanyNm())
                        .set(qCompany.ceo, company.getCeo())
                        .set(qCompany.bizno, company.getBizno())
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
            } else if (company.isDeleted()) {
                result = delete(qCompany)
                        .where(qCompany.id.eq(company.getId()))
                        .execute();
            }
        }
        return result;
    }

단위 테스트 실행 순서

CompanyServiceTest.java
public static long testId = 0; 전역변수를 선언해주고 기존 result를 testID로 바꿔준다. 테스트코드를 한번에 실행이 가능해졌다.
하지만 CompanyServiceTest를 실행시키면 update가 create보다 먼저 실행되어 오류가 발생한다. 따라서 단위 테스트의 실행 순서를 정해주는 것이 필요하다.

CompanyServiceTest.java

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class CompanyServiceTest {

@FixMethodOrder 어노테이션을 추가하고 메소드의 정렬 방식을 이름 순으로 지정해준다.

  public void test1_SaveByQueryDsl_create(){
  public void test2_SaveByQueryDsl_update(){
  public void test3_SaveByQueryDsl_delete(){

메소드의 이름을 변경해주면 create - update - delete 순으로 정상적으로 작동하게 된다.

@FixMethodOrder 어노테이션 외에도 @Order 어노테이션으로도 설정이 가능하다.


리팩토링을 해보자.. 중간에 상담 다녀와서 설명을 못들었다..ㅜ
CompanyService.java에서 getByQueryDsl 메소드를 지우고 getOneByQueryDsl 메소드를 생성하자

    public Company getOneByQueryDsl(long id) {
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qCompany.id.eq(id));
        Company company = select()
                .from(qCompany)
                .where(builder)
                .fetchOne();
        return company;
    }

CompanyServiceTest.java에서도 마찬가지로 test_GetQueryDslByString 메소드를 지우고 test3_SaveByQueryDsl_selectOne 메소드를 생성한다.

    @Test
    public void test3_SaveByQueryDsl_selectOne(){ //test + test할 메소드명
        //given : 사전 준비
        String companyNm = "당근마켓";

        //when : 실제 액션
        Company result = this.companyService.getOneByQueryDsl(testId);

        //then : 결과 확인
        assertTrue(result.getCompanyNm().equals(companyNm));
    }

오후 수업

대부분의 spring framework의 구조는 axboot와 비슷하다.

AXBoot resources

axboot-common.properties
공통적으로 올라가는 환경파일 지정. 지정을 안하면 기본 형식으로 올라간다. ex) server port를 지정하지 않으면 8080으로 지정되는 것.

axboot-local.properties / axboot-production.properties
개발과 운영단을 나눠서 지정해놓은 것. 개발시에는 local에 지정해서 하고, 개발 환경이 다른 곳에 배포할때는 production에 지정해서 한다.
db가 바뀌었을 때 url만 바꿔주면 바로 변경된 db와 연결된다. axboot만이 아니라 다른 프로젝트도 마찬가지

AXBootApplication.java 파일에 @PropertySource(value = {"classpath:axboot-common.properties", "classpath:axboot-${spring.profiles.active:local}.properties"}) 이렇게 지정되어 있어서 local.properties가 지정되어 실행된다.

src/main/resources/messages
messages_ko.properties / messages_en.properties
다국어 처리용. 지정된 값을 수정하여 사용하거나 다른 언어를 추가해서 사용 가능하다.

src/main/resources/template
JSBasicTemplate.tpl / JSPBasicTemplate.tpl
메뉴 추가시에 해당 템플릿을 읽어서 기본 메뉴를 생성한다.
메뉴 생성시 생성되는 메뉴를 변경하고자 하면 여기서 수정하면 된다.

AXBootSecurityConfig.java
보완관련 문서
ignorePages는 원래는 세션이 없으면 튕겨서 화면을 볼 수 없지만 여기에 추가되어있는 페이지는 세션이 없어도 보여준다. 로그인을 안해도 서비스되는 화면단이다.
스프링 시큐리티에서 지원해준다?

이정도로만 알아도 문제는 없으니 더 궁금한 것은 구글선생님한테 여쭤보자,,


Spring Framework

Spring Framework

  • 자바 플랫폼을 위한 오픈소스 애플리케이션 프레임워크로서 엔터프라이즈급 애플리케이션을 개발하기 위한 모든 기능을 종합적으로 제공하는 경량화된 솔루션

MVC Model2

  • Model View Controller 구조로 사용자 인터페이스와 비지니스 로직을 분리하여 개발 하는 것

자세한 내용은 구글에서 찾아보자,,


단위 테스트

오전에 진행한 단위 테스트 모듈을 이어서 만들어보자
기존 getByQueryDsl, saveByQueryDsl은 객체를 리스트로 반환하는데, 이것을 하나씩 반환하도록 메소드를 추가하자

getOneByQueryDsl & saveOneByQueryDsl

CompanyService.java 에 아래 코드를 추가한다.

    public Company getOneByQueryDsl(long id) {
        BooleanBuilder builder = new BooleanBuilder();
        builder.and(qCompany.id.eq(id));
        Company company = select()
                .from(qCompany)
                .where(builder)
                .fetchOne();
        return company;
    }

    @Transactional
    public Long saveOneByQueryDsl(Company company){
        Long result = 0L;
        if (company.isCreated()) {
            Company rtnObj = save(company);
            result = rtnObj.getId();
        } else if (company.isModified()) {
            result = update(qCompany)
                    .set(qCompany.companyNm, company.getCompanyNm())
                    .set(qCompany.ceo, company.getCeo())
                    .set(qCompany.bizno, company.getBizno())
                    .where(qCompany.id.eq(company.getId()))
                    .execute();
        } else if (company.isDeleted()) {
            result = delete(qCompany)
                    .where(qCompany.id.eq(company.getId()))
                    .execute();
        }
        return result;
    }

생성해야 할 단위 테스트 모듈의 기본 구조를 먼저 보면 test21, test22 ... 이런식으로 진행된다. 앞에서 @FixMethodOrder(MethodSorters.NAME_ASCENDING) 을 지정해 줬기 때문에 이름 순으로 단위테스트가 진행되기 때문이다.
test1, 2, 3, ... 식으로 작명을 하게 되면 메소드명을 텍스트로 인식하기 때문에 test1, test2, test22, test23, test3 ... 순서로 테스트가 진행되어 오류가 발생한다. 따라서 아래와 같은 구조로 메소드명을 설정한다.

    @Test
    public void test12_SaveByQueryDsl_updates(){
        //given
        //when
        //then
    }
    @Test
    public void test13_getByQueryDsl_selectOne(){ //test + test할 메소드명
        //given : 사전 준비
        //when : 실제 액션
        //then : 결과 확인
    }
    @Test
    public void test15_SaveByQueryDsl_deletes(){
        //given
        //when
        //then
    }
    @Test
    public void test21_SaveByQueryDsl_create() {
        //given
        //when
        //then
    }
    @Test
    public void test22_SaveByQueryDsl_update() {
        //given
        //when
        //then
    }
    @Test
    public void test25_SaveByQueryDsl_delete() {
        //given
        //when
        //then
    }

CompanyServiceTest.java

    @Test
    public void test21_SaveByQueryDsl_create() {
        //given
        Company company = new Company();
        company.setCompanyNm("리디북스");
        company.setCeo("리디");
        company.setBizno("777888");
        company.set__created__(true);

        //when
        testId = this.companyService.saveOneByQueryDsl(company);

        //then
        assertTrue(testId > 0);
    }

    @Test
    public void test22_SaveByQueryDsl_update() {
        //given
        Company company = new Company();
        company.setId(testId);
        company.setCompanyNm("리디북스");
        company.setCeo("성훈");
        company.setBizno("777999");
        company.set__modified__(true);

        //when
        Long result = this.companyService.saveOneByQueryDsl(company);

        //then
        assertTrue(result > 0);
    }

    @Test
    public void test25_SaveByQueryDsl_delete() {
        //given
        Company company = new Company();
        company.setId(testId);
        company.set__deleted__(true);

        //when
        testId = this.companyService.saveOneByQueryDsl(company);

        //then
        assertTrue(testId > 0);
    }

CompanyServiceTest 코드를 실행해보면 순서대로 실행되는 것을 볼 수 있다.

기능이 제대로 동작하는 것을 확인했으니 컨트롤러를 만든다.
CompanyController.java에 아래 코드를 추가해준다.

    @RequestMapping(value = "/queryDsl/selectOne", method = RequestMethod.GET, produces = APPLICATION_JSON)
    @ApiImplicitParam(name = "id", value = "ID", dataType = "Long", paramType = "query")
    public Company selectOne(long id) {
        Company company = this.companyService.getOneByQueryDsl(id);
        return company;
    }

    @RequestMapping(value = "/queryDsl/saveOne", method = RequestMethod.PUT, produces = APPLICATION_JSON)
    public ApiResponse saveOne(@RequestBody Company company) {
        companyService.saveOneByQueryDsl(company);
        return ok();
    }

과정을 마치고 swagger를 확인해보면 id를 입력했을 때 결과가 리스트가 아니라 객체 하나로 나오고, create, update, delete 기능이 제대로 동작하는 것을 확인할 수 있다.

profile
yesjm's second brain

0개의 댓글