# JUNIT를 사용한 VIEW의 Form 테스트하기

- Event 정보

- Form 화면 , 등록 컨트롤러


1. Event.java : 이벤트 정보 

package com.example.demo.junitFormTest;

public class Event {

    private String eventName;
    private String eventDescription;
    private Integer eventCount;

    public Integer getEventCount() {
        return eventCount;
    }

    public void setEventCount(Integer eventCount) {
        this.eventCount = eventCount;
    }

    public String getEventName() {
        return eventName;
    }

    public void setEventName(String eventName) {
        this.eventName = eventName;
    }

    public String getEventDescription() {
        return eventDescription;
    }

    public void setEventDescription(String eventDescription) {
        this.eventDescription = eventDescription;
    }
}

2. FormController.java : 이벤트 화면 및 이벤트 등록(이벤트 정보 확인) 

package com.example.demo.junitFormTest;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.*;

@Controller
@RequestMapping("junitForm")
public class FormController {

    /**
     * 이벤트 등록 화면 컨트롤러
     * @param model
     * @return
     */
    @GetMapping("/formEvent")
    public String formEvent(Model model) {
        // formEvent 화면에 Event 그릇 내려 주기
        model.addAttribute("event", new Event());
        return "/junit/FormTest/formEvent";
    }

    /***
     * 이벤트 정보 확인
     * @param event
     * @param bindingResult
     * @return
     */
    @PostMapping("/regEvent")
    @ResponseBody
    public Event regEvent(
            @ModelAttribute Event event,
            // 값을 바인딩 할 수 없는 경우네는 BindingResult 4000 에러
            // 이벤트 변수 타입이 맞지 않은 경우 null 처리
            BindingResult bindingResult) {
        if(bindingResult.hasErrors()){
            // binding 에러가 된 경우, 에러 종류 찍기
            for (ObjectError allError : bindingResult.getAllErrors()) {
                System.out.println(allError.toString());
            }
        }
        return event;
    }

}

3. FormControllerTest.java : 이벤트 화면 및 이벤트 등록(이벤트 정보 확인) 

package com.example.demo.junitFormTest;

import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import javax.swing.*;

import static org.junit.jupiter.api.Assertions.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@WebMvcTest
@RunWith(SpringRunner.class)
class FormControllerTest {

    @Autowired
    MockMvc mockMvc;

    /**
     * 이벤트 화면 테스트
     * @throws Exception
     */
    @Test
    void formEvent() throws Exception {
        // 이벤트 화면 테스트하기
        mockMvc.perform(get("/junitForm/formEvent"))
                .andDo(print())
                // 이벤트 화면 이름 확인하기
                .andExpect(view().name("/junit/FormTest/formEvent"))
                // 이벤트 화면의 model 정보 확인하기
                .andExpect(model().attributeExists("event"))
        ;
    }

    @Test
    void regEvent() throws Exception {
        // 이벤트 regEvent 확인하기
        mockMvc.perform(post("/junitForm/regEvent")
                    // 파라미터 정보
                    .param("eventName", "testEvent")
                    .param("eventDescription", "이벤트를 테스트합니다")
                    .param("eventCount", "12")
                )
                .andDo(print())
                // 파라미터 정보 검증하기
                .andExpect(jsonPath("eventName").value("testEvent"))
                .andExpect(jsonPath("eventDescription").value("이벤트를 테스트합니다"))
                .andExpect(jsonPath("eventCount").value("12"))
                .andExpect(status().isOk())
        ;

        // 이벤트 regEvent 확인하기
        mockMvc.perform(post("/junitForm/regEvent")
                // eventCount는 숫자가 되어야 하나 String 값이 들어가서 바인딩 에러가 발생한다.
                .param("eventName", "testEvent")
                .param("eventDescription", "이벤트를 테스트합니다")
                .param("eventCount", "바인딩 에러 만들기")
                )
        ;
    }
}

4.  테스트 화면 결과

 

    - eventCount에 숫자 대신 String을 넘음으로써 바인딩 에러 발생.

블로그 이미지

미나미나미

,

[SpringMVC] 커스텀 컨트롤러 어노테이션(Annotation) 만들기 

 


1. 어노테이션 생성  

package com.example.demo.annotation;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.lang.annotation.*;

/**
 * CustomAnnotation.java
 * /custom Controller 생성
 * Runtime 까지 유지
 */
@Documented
// 문서에 그 애노테이션에 대한 정보를 표기할지 결정
@Target({ElementType.METHOD})
// 어디에 사용할 수 있는지를 결정
@Retention(RetentionPolicy.RUNTIME)
//  언제까지 유지할 것인가
//  Source : 소스 코드까지만 유지, 즉 컴파일 하면 해당 애노테이션 정보는 사라진다는 이야기
//  Class : 컴파일 한 .class 파일에도 유지. 즉 런타임 시, 클래스를 메모리로 읽어오면 해당 정보는 사라진다.
//  Runtime : 클래스 메모리에 읽어왔을 떄 까지 유지! 코드에서 이 정보를 바탕으로 특정 로직을 실행 할 수 있다.
@RequestMapping(method = RequestMethod.GET , value = "/custom")
//  커스텀한 애노테이션을 만들 수 있다.
public @interface CustomAnnotation {
}

 

2. 어노테이션 사용한 컨트롤러 생성 

package com.example.demo.annotation;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * CustomController.java
 */
@Controller
@RequestMapping("/testAnnotation")
public class CustomController {

    /**
     * /testAnnotation/custom 으로 접근 가능
     * @return
     */
    @CustomAnnotation
    @ResponseBody
    public String custom(){
        return "custom";
    }
}

 

3. 컨트롤러 테스트 코드 작성 

@WebMvcTest
@RunWith(SpringRunner.class)
class CustomControllerTest {

    @Autowired
    MockMvc mockMvc;

    @Test
    void custom() throws Exception{
        mockMvc.perform(get("/testAnnotation/custom"))
                .andDo(print())
                .andExpect(status().isOk())
        ;
    }
}

 

4. 결과화면 

 

블로그 이미지

미나미나미

,

[JavaScript] ES6 Class Static Method

 

클래스에 static으로 명시된 함수는 클래스로 호출이 가능하나, 생성된 인스턴스에서는 사용이 불가능하다.

 

class Car {
    constructor(name='없음', passengers='0', price='0') {
        this.name = name;
        this.passengers = passengers;
        this.price = price;
    }

    print() {
        console.log(
            'name => ' + this.name, 
            '/ passengers => ' + this.passengers, 
            '/ price => ' + this.price
        );
    }

    static carPrint(){
        console.log('static carPrint 스태틱 메소드 출력');
    }
}

// 클래스 스태틱 메소드 호출
Car.carPrint();
// static carPrint 스태틱 메소드 출력

var sonata = new Car('sonata' , '4' , 10000);
sonata.print();
//name = >sonata / passengers = >4 / price = >10000
sonata.carPrint(); // 스태틱 메소드 호출
// VM4320:27 Uncaught TypeError: sonata.carPrint is not a function at <anonymous>:27:8

블로그 이미지

미나미나미

,

# Class 생성 및 인스턴스 생성 

class Car {
    constructor(name, passengers, price) {
        this.name = name;
        this.passengers = passengers;
        this.price = price;
    }

    print() {
        console.log(
            'name => ' + this.name, 
            '/ passengers => ' + this.passengers, 
            '/ price => ' + this.price
        );
    }
}

var sonata = new Car('sonata' , '4' , 10000);
sonata.print();
// name = >sonata / passengers = >4 / price = >10000

# 결과 화면 

 


# Class  인스턴스  생성시 초기화

class Car {
   // 인스턴스 생성시, 초기화 값 지정
    constructor(name='없음', passengers='0', price='0') {
        this.name = name;
        this.passengers = passengers;
        this.price = price;
    }

    print() {
        console.log(
            'name => ' + this.name, 
            '/ passengers => ' + this.passengers, 
            '/ price => ' + this.price
        );
    }
}

var sonata = new Car('sonata' , '4' , 10000);
sonata.print();
//name = >sonata / passengers = >4 / price = >10000

// 인스턴스 생성시, 인자값 초기화 지정값 사용
var notCar = new Car();
notCar.print();

 

# 결과 화면

블로그 이미지

미나미나미

,

call 함수는 결국 this를 조작하는 거 같다. 그러하다...


# 문서 call 함수 정의

- call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다

 

# 문서 call 함수 설명

- call()은 이미 할당되어있는 다른 객체의 함수/메소드를 호출하는 해당 객체에 재할당할때 사용됩니다. this는 현재 객체(호출하는 객체)를 참조합니다. 메소드를 한번 작성하면 새 객체를 위한 메소드를 재작성할 필요 없이 call()을 이용해 다른 객체에 상속할 수 있습니다.

 

솔직히 잘모르겠다. 그래서 예시를 만들어보았다.

 

# developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Function/call

 

Function.prototype.call()

call() 메소드는 주어진 this 값 및 각각 전달된 인수와 함께 함수를 호출합니다.

developer.mozilla.org

구문

func.call(thisArg[, arg1[, arg2[, ...]]])

매개변수

thisArg func 호출에 제공되는 this의 값.

this는 메소드에 의해 보이는 실제값이 아닐 수 있음을 주의하세요: 메소드가 비엄격 모드 코드 내 함수인 경우, nullundefined는 전역 객체로 대체되고 원시값은 객체로 변환됩니다.

arg1, arg2, ...

객체를 위한 인수.

반환값(Return Value)

this 와 arguments 를 매개로 호출된 함수의 반환값


#예시

서버 3대 ServerA, ServerB, ServerC의 정보를 담은 객체와 출력하는 함수 만들기

var serverInfoPrint = {
  ip: "없음",
  address: "없음",
  name: "없음",
  print: function (conIp, conName) {
    return (
      "서버 정보 : " +
      this.ip +
      " , " +
      this.address +
      " , " +
      this.name +
      "/ 접속 정보 :" +
      conIp +
      " , " +
      conName
    );
  },
};

var serverA = {
  ip: "10.10.10.10",
  address: "서울 B구역",
  name: "개발 서버",
};

var serverB = {
  ip: "10.124.140.111",
  address: "부산 C구역",
  name: "백업 서버",
};

var serverC = {
  ip: "미할당",
  address: "대구 Q구역",
  name: "가상 서버",
};

// serverInfoPrint의 this를 사용하는 경우, 인자값을 안주는 경우
console.log(serverInfoPrint.print());
// serverInfoPrint의 this를 사용하는 경우, 인자값을 주는 경우
console.log(serverInfoPrint.print("0.0.0.0" , "테스트계정"));

// serverA의 this를 사용하는 경우, 인자값을 안주는 경우
console.log(serverInfoPrint.print.call(serverA));
// serverA의 this를 사용하는 경우, 인자값을 주는 경우
console.log(serverInfoPrint.print.call(serverA, "10.200.10.11", "테스트 계정"));
// serverA의 this를 사용하는 경우, 인자값을 주는 경우
console.log(serverInfoPrint.print.call(serverA, "0.0.0.0", "마스터 계정"));

// serverB의 this를 사용하는 경우, 인자값을 주는 경우
console.log(serverInfoPrint.print.call(serverB, "210.120.33.111", "유저 계정"));
// serverC의 this를 사용하는 경우, 인자값을 주는 경우
console.log(serverInfoPrint.print.call(serverC, "123.0.13.231", "테스트 계정"));

/**
서버 정보 : 없음 , 없음 , 없음/ 접속 정보 :undefined , undefined
서버 정보 : 없음 , 없음 , 없음/ 접속 정보 :0.0.0.0 , 테스트계정
서버 정보 : 10.10.10.10 , 서울 B구역 , 개발 서버/ 접속 정보 :undefined , undefined
서버 정보 : 10.10.10.10 , 서울 B구역 , 개발 서버/ 접속 정보 :10.200.10.11 , 테스트 계정
서버 정보 : 10.10.10.10 , 서울 B구역 , 개발 서버/ 접속 정보 :0.0.0.0 , 마스터 계정
서버 정보 : 10.124.140.111 , 부산 C구역 , 백업 서버/ 접속 정보 :210.120.33.111 , 유저 계정
서버 정보 : 미할당 , 대구 Q구역 , 가상 서버/ 접속 정보 :123.0.13.231 , 테스트 계정
 */

 

 

# 결과화면

 

블로그 이미지

미나미나미

,

[JAVA] String []를 ArrayList변환

 

import java.util.ArrayList;
import java.util.Arrays;

public class StringArrToList {
    public static void main(String[] args) {
        String[] words = new String[] { "asd", "qqq", "aaa", "poi" };

        ArrayList<String> wordList = new ArrayList(Arrays.asList(words));

        for (String s : wordList) {
            System.out.println(s);
        }
    }
}

블로그 이미지

미나미나미

,

[JAVA] ArrayList를 String[] 변환 여러가지 방법

 

import java.util.ArrayList;

public class ListToStringArr {
    public static void main(String[] args) {
        ArrayList<String> testList = new ArrayList<String>();
        testList.add("철수");
        testList.add("영미");
        testList.add("김천");

        testList.forEach(
            x -> System.out.println( "testList => " + x)
        );

        // String[] 배열로 복사
        // testList.toArray 자체가 object[] 반환. 
        // 결론적으로 배열은 목록의 데이터로 채워지고 반환됨
        // new String[testList.size()] 보다 new String[0]로 사용하는 것이 더 좋다고 함.
        String[] strArr1 =  testList.toArray(new String[testList.size()]);
        String[] strArr2 =  testList.toArray(new String[0]);

        // JAVA 8 Stream을 사용한 방식
        String[] strArr3 = testList.stream().toArray(String[]::new);

        for(String s : strArr1){
            System.out.println("strArr1 => " + s);

        }

        for(String s : strArr2){
            System.out.println("strArr2 => " + s);
        }

		// JAVA 8 Stream을 사용한 결과 확인
        for(String s : strArr3){
            System.out.println("strArr3 => " + s);
        }
    }
}

 

# 결과화면

 

 

블로그 이미지

미나미나미

,

[javascript] arguments 인자값의 변화

 

 

 - 함수 인자값을 함수 실행 중 변경시 변경된다.

function argumentTest(a, b) {
  console.log("a+b", a + b);
  b = 10;
  console.log(arguments);
  console.log("a+b", a + b);
}

function argumentTest2(a, b) {
  console.log(arguments);
  b = 10;
}

argumentTest(1, 2);
argumentTest(1, 10);

/**
     a+b 3
    VM854:4 Arguments(2) [1, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    VM854:5 a+b 11
    VM854:2 a+b 11
    VM854:4 Arguments(2) [1, 10, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    VM854:5 a+b 11
 */
 
 
 // ------------------------------------------
 // object는 값에 변화가 없음
 
 var o = { 0: 1, 1: 2 };
console.log(o);
// VM888:2 {0: 1, 1: 2}

var a = o[0],
  b = o[1];

b = 10;
console.log(o);
// VM888:7 {0: 1, 1: 2}

 // ------------------------------------------
블로그 이미지

미나미나미

,