(1)  테스트 코드   

 

 TDD(Test Driven Development)는 테스트가 주도하는 개발을 말하며 테스트 코드를 먼저 작성하는 것부터 시작한다. 아래 그림과 같이 RED-GREEN Cycle을 말한다.

 

  1. RED: 항상 실패하는 테스트를 먼저 작성한다.
  2. GREEN: 테스트가 통과하는 프로덕션 코드를 작성한다.
  3. REFACTOR: 테스트가 통과하면 프로덕션 코드를 리팩토링한다. 

 

출처: https://hyem-study.tistory.com/98?category=893981

 

 반면 단위 테스트는 TDD의 첫 번째 단계인 기능 단위의 테스트 코드를 작성하는 것을 말한다. TDD와 달리 테스트 코드를 꼭 먼저 작성하는 것이 아니고 리팩토링 작업도 포함되지 않는다. 순수하게 테스트 코드만 작성하는 것을 말한다. 

 


 

    (2) 단위테스트 장점    

 

 위키피디아에서의 단위 테스트의 장점은 다음과 같다.

 

  • 개발단계 초기에 문제를 발견하게 도와준다.
  • 개발자가 나중에 코드를 리팩토링하거나 라이브러리 업그레이드 등에서 기존 기능이 올바르게 작동하는지 확인할 수 있다. 
  • 기능에 대한 불확실성을 감소시킬 수 있다.
  • 시스템에 대한 실제 문서를 제공한다. 즉, 단위 테스트 자체를 문서로 사용할 수 있다. 

 

 이 밖에도 더 많은 장점이 있는데 단위 테스트를 하기 전의 개발 방식은 보통 다음가 같은 것이다. 

 

  1. 테스트 코드를 작성한다.
  2. 프로그램(Tocmat 등)을 실행한다.
  3. Postman과 같은 API 테스트 도구로 HTTP 요청한다.
  4. 요청 결과를 출력(console.log, System.out.println 등)하여 눈으로 검증한다.
  5. 결과가 다르면 다시 프로그램을 중지하고 코드를 수정한다. 

 여기서 2~5번은 매번 코드를 수정할 때마다 반복해야 한다. 

 


 

    (3)  테스트 코드 작성하기    

 

 프로젝트 내 [src] - [main] - [java] 폴더의 마우스 오른쪽 버튼을 클릭하여 [New ▶ Package]를 차례로 선택해서 생성한다. 일반적으로 패키지명은 웹 사이트 주소의 역순으로 한다고 한다. 예를 들어, admin.daldalhade.com이라는 사이트라면 패키지명은 com.daldalhade.admin으로 하면 된다. 

 

 

 패키지가 생성됐으면 패키지를 마우스 오른쪽 버튼으로 클릭하고 [New ▶ Java Class]를 차례로 선택하면 된다. 클래스의 이름은 Application으로 설정한다.

 

 

 

그리고 클래스의 코드를 다음과 같이 작성한다. 

 

package com.daldalhada.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

 

 방금 생성한 Application 클래스는 프로젝트의 메인 클래스가 된다. @springBootApplication으로 인해 스프링 부트의 자동 설정, 스프링 Bean 읽기와 생성이 모두 자동으로 설정된다. 특히,  @springBootApplication이 있는 위치부터 설정을 읽기 때문에 이 클래스는 항상 프로젝트의 최상단에 위치해야 한다. 

 

 main 메소드에서 실행하는 SpringApplication.run으로 인해 내장 WAS를 실행한다. 여기서 내장 WAS는 별도로 외부에 WAS를 두지 않고 애플리케이션을 실행할 때 내부에서 WAS를 실행하는 것을 이야기 한다. 이러면 항상 서버에 톰캣을 설치할 필요가 없게 되고, 스프링 부트로 만들어진 Jar 파일(실행 가능한 Java 패키징 파일)로 실행하면 된다. 

 

 스프링 부트는 언제 어디서나 같은 환경에서 스프링 부트를 배포할 수 있기 때문에 내장 WAS를 사용하는 것을 권장하고 있다. 외장 WAS를 쓰게 되면 모든 서버는 WAS의 종류와 버전, 설정일 일치시켜야 하기에 복잡하다. 1대면 문제가 없지만 30대의 서버가 존재할 때 WAS의 버전을 올린다고 하면 실수할 여지가 많고 시간적인 면에서도 비효율적이 된다. 

 

 

 이번에는 테스트를 위한 Controller를 만들기 위해 패키지 하위에 web이라는 패키지를 만든다.

 

 

 그리고 테스트를 해 볼 Hello Cotroller를 하나 생성한다.

 

 

 

package com.daldalhada.springboot.web;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String hello() {
        return "hello";
    }
}

 

 위의 코드 중 @RestController는 JSON을 반환하는 컨트롤러로 만들어 주는 역할을 하고 @GetMapping은 HTTP 메서드인 Get의 요청을 받을 수 있는 API를 만들어 준다. 

 

 작성한 코드가 제대로 작동하는지 테스트를 하기 위해 WAS를 실행하지 않고 테스트 코드로 검증해보기 위해 [src]-[test]-[java] 디렉토리에 앞에 생성했던 패키지를 그대로 다시 생성한다. 그리고 테스트 코드를 작성할 클래스를 생성한다. 일반적으로 테스트 클래스는 대상 클래스 이름에 Test를 붙인다고 한다. 따라서, HelloControllerTest로 생성한다. 

 

 

 생성되면 다음과 위의 사진과 같게 되고 HelloControllerTest에 코드를 추가한다. 

 

package com.daldalhada.springboot;

import com.daldalhada.springboot.web.HelloController;
import org.junit.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 static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@RunWith(SpringRunner.class)
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void hello_return() throws Exception {
        String hello = "hello";

        mvc.perform(get("/hello"))
                .andExpect(status().isOk())
                .andExpect(content().string(hello));
    }
}

 

 위의 코드는 다음과 같다.

 

1. @RunWith(SpringRunner.class)

  • 테스트를 진행할 때 JUnit에 내장된 실행자 외에 다른 실행자를 실행시키는데 여기서는 SpringRunners라는 스프링 실행자를 사용한다.
  • 즉, 스프링 부트 테스트와 JUnit 사이를 연결하는 역할을 한다.

2. @WebMvcTest

  • 수 많은 스프링 테스트 어노테이션 중, Web(Spring MVC)에 집중할 수 있는 어노테이션이다. 
  • 스프링이 관리하는 모든 빈을 등록시켜 테스트하는 @SpringBootTest와 달리 @WebMvcTest는 web 관련 빈들만 등록하므로 가볍다.

3. @Autowired

  • 스프링이 관리하는 빈을 주입 받는다.

4. private MockMvc mvc

  • 웹 API를 테스트 할 때 사용되고 스프링 MVC 테스트의 시작점이다. 
  • 이 클래스를 통해 HTTP의 메서드인 GET, POST 등에 대한 API 테스트를 할 수 있다. 

5. mvc.perform(get("/hello"))

  • MockMvc를 통해 /hello 주소로 HTTP GET 요청을 한다. 
  • 체이닝이 지원되어 .andExpect에 여러 검증 기능을 이어서 선언할 수 있다.

6. andExpect(status().isOk())

  • mvc.perform의 결과를 검증하며 특히, HTTP Header의 Status를 검증한다. 
  • isOk()는 Status code가 200인지 아닌지 검증한다.

7. andExpect(content().string(hello))

  • 응답 본문의 내용을 검증한다.
  • Controller에서 "hello"를 리턴하기 때문에 값이 맞는지 검증하는 역할을 한다.

 

 HelloControllerTest.java에서 빨간색으로 표시된 화살표 부분을 클릭하고 Run HelloControllerTest.java를 클릭해 테스트 코드를 실행해보면 테스트가 통과되었다면 Tests passed가 뜬다. 

 

 HelloControllerTest.java에서 빨간색으로 표시된 화살표 부분을 클릭하고 Run HelloControllerTest를 클릭해 테스트 코드를 실행해보면 테스트가 통과되었다면 Tests passed가 뜬다. 

 

 이번에는 Application.java로 가서 수동으로 실행해 정상적으로 값이 출력되는지 확인해본다. 빨간색으로 표시된 화살표 버튼을 클릭하고 Run Application을 클릭하면 톰캣 서버가 8080포트로 실행되었다는 것이 콘솔 창에 출력된다. 

 

 

 

 

 

 이제 웹 브라우저에서 localhost:8080/hello로 접속하여 문자열 hello가 잘 나오는지 확인한다. 웹 브라우저를 열어 localhost:8080/hello로 접속한다.

 

 하지만, localhost:8080/login으로 바뀌어 다음과 같은 화면이 뜨는 경우가 발생할 수 있다. 처음에는 포트 충돌 문제인지 알고 포트를 변경하는 방법을 시도했다.

 

 포트를 변경하는 방법은 먼저, [build]-[resources]-[main] 또는 [src]-[main]-[resource]의  application.properties을 찾는다. 

 

 

 

 application.properties을 열어 server.port 부분을 원하는 포트 번호로 수정한다. 

 

 

 하지만, 포트를 변경해도 소용없었고 구글링 하던 중 스택 오버 플로우에서 Username은 user로 Password는 콘솔창에 나와있는 password를 치면 된다고 한다.

 

 

 결과는 정상적으로 출력되었고 테스트 코드의 결과와 같은 것을 알 수 있다.

 

'스프링 부트 프로젝트 > 테스트 코드 작성' 카테고리의 다른 글

4. 롬복 설치하기  (0) 2020.10.05

 

   개요   

 

 


 

   (1) 초창기 컴퓨터(1940년대)  

 

 최초의 컴퓨터인 에니악은 30톤 규모의 거대한 계산기로 미사일 탄도를 계산하기 위해 제작되었다. 에니악은 키보드, 마우스, 모니터와 같은 컴퓨터 자원이 없었고 운영체제 또한 없었다. 진공관이라는 소자를 사용하여 진공관이 켜지면 1, 꺼지면 0이라고 판단했고 이는 컴퓨터가 2진법을 사용하는 계기가 되었다. 에니악은 전선으로 논리회로를 구성하여 원하는 결과만 얻는 방식으로 다른 계산이나 수식을 사용하려면 전선을 다시 연결해야 했다. 

 


 

   (2) 일괄 작업 시스템(1950년대)  

 기술 발전을 거쳐 진공관에서 IC(Integrated Circuit)라는 칩으로 변화했다. 이 칩은 진공관과 전선으로 만들어진 논리회로를 아주 작은 크기로 구현하였다. 미약하지만 CPU와 메인 메모리가 있었으나 키보드, 모니터와 같은 입출력 장치가 없었다. 대신, 천공카드 리더(OMR)와 라인 프티러를 입출력 장치로 사용했다. 

 

 천공카드 리더와 라인 프리터를 사용함으로써 지금의 프로그래밍과 유사한 방식으로 다양한 소프트웨어를 개발할 수 있게 되었다. 하지만, 한 번에 한 가지 작업만 할 수 있었다. 이처럼 모든 작업을 한꺼번에 처리해야 하고 프로그램 실행 중간에 사용자가 데이터를 입력하거나 수정하는 것이 불가능한 시스템을 일괄 작업 시스템(Batch Job System) 또는 일괄 처리 시스템이라고 한다. 일괄 작업 시스템은 운영체제가 사용되었으며 메인 메모리가 운영체제의 상주 영역과 사용자의 사용 영역으로 나뉘었다.

 

 


 

   (3) 대화형 시스템(1960년대 초)    

 

 1960년대 초반에는 모니터와 키보드가 등장했다. 이들은 비효율적인 일괄 작업 시스템을 대화형 시스템(Interactive System)으로 바꿔 놓았다. 일괄 작업 시스템과는 달리 대화형 시스템은 작업 중간에 사용자가 입력을 하고나 사용자에게 중간 결과값을 보여줄 수 있게 되었고 또한 중간 결과값을 출력하여 프로그램에 이상이 있는지 혹은 정상적으로 진행되는지 확인할 수 있게 되었다. 

 

 하지만 대화형 시스템에도 문제점이 있다. 일괄 작업 시스템은 입출력이 거의 없어 작업 시간을 예측할 수 있지만 대화형 시스템의 경우 작업 시간을 예측하기 어려웠다.  

 

 

 



   (4) 시분할 시스템(1960년대 말)   

 

 1960년대 후반에는 컴퓨터의 크기가 작아지고 계산 능력이 향상되었다. 하지만 상당히 비싸서 한 번에 하나의 작업만 수행하는 것은 낭비라 효율적인 방법이 필요했다. 연구가 진행되면서 다중 프로그래밍(multiprogramming) 기술이 개발되었다. 이는 하나의 CPU로 여러 작업을 동시에 실행할 수 있는 기술로 한 번에 하나의 작업만 처리할 수 있는 일괄 작업 시스템에 비해 효율성이 뛰어났다.

 

 하지만 여러 작업이 하나의 CPU를 공동으로 사용하면 작업이 끊겨 보일 텐데 어떻게 이를 구현한 것일까? 방법은 시간을 분할하는 것이였다. 다중 프로그래밍 시스템에서는 CPU 사용 시간을 아주 잘게 쪼개어 여러 작업에 나누어 준다. 

 

 예를 들어, A~C 작업을 동시에 진행한다고 가정한다. CPU가 각 작업에 1초를 할당하면 작업이 끊어지면서 실행되겠지만 0.1초를 할당하면 각각 A~C 작업은 0.1초씩 할당되고 A 작업은 0.3초 뒤에 다시 CPU를 얻어 작업할 수 있다. 이처럼 시간 분배를 최대한 적게하여 반복되면 작업이 동시에 실행되는 것처럼 보인다. 

 

 

 

 이처럼 여러 작업을 조금씩 처리하여 작업이 동시에 이루어지는 것처럼 보이게 하는 것을 시분할 시스템(Time Sharing System) 또는 다중 작업(Multitasking)이라고 한다. CPU 사용 시간을 잘게 쪼개어 나눠줌으로써 모든 작업이 동시에 처리되는 것처럼 보인다. 이 때의 시간 조각들을 타임 슬라이스(Time Slice) 또는 타임 퀀텀(Time Quantum)이라고 한다. 오늘날 대부분 시분할 시스템이 사용된다. 

 

 하지만, 시분할 시스템에도 단점이 존재한다. 시스템 내에 많은 작업이 공존할 경우, 중요한 작업이 일정 시간 안에 끝나는 것을 보장하지 못한다는 것이다. 이는 특정 시스템에서 일정 시간 안에 작업이 처리되도록 보장하는 실시간 시스템(Real-time System)을 사용한다. 

 

시분할 시스템에서 동시에 실행되는 작업의 개수를 멀티 프로그래밍 수준(Level of Multiprogramming) 또는 멀티 프로그래밍 정도라고 한다. 일괄 작업 시스템은 멀티프로그래밍 수준이 1이고 위의 그림에서는 작업이 3개이므로 멀티프로그래밍 수준이 3이 된다. 

 

 시분할 시스템에서 여러 작업이 동시에 실행할 수 있다는 것은 한 사람이 여러 프로그램을 동시에 실행할 수 있다는 의미이기도 하고 여러 사람이 동시에 작업할 수 있다는 의미이기도 하다. 즉, 시분할 시스템은 하나의 컴퓨터에서 여러 사람이 동시에 사용할 수 있는 다중 사용자 시스템(Multi-user System)을 가능하게 했다. 값비싼 컴퓨터를 한 사람 또는 하나의 작업이 독점하는 것이 아닌 여러 사람이 동시에 사용할 수 있는 환경이 만들어졌다.

 

 



   (5) 분산 시스템(1970년대 말)   

 

 1970년대 말에는 인터넷이 등장했으며 서로 호환되지 않는 LAN들을 하나로 묶는 아르파넷(ARPAnet)이 만들어 졌고 컴퓨터 간 네트워킹을 위한 TCP/IP라는 프로토콜이 정의되었다.

 

 또한, 개인용 컴퓨터와 인터넷이 보급되면서 값이 싸고 크기가 작은 컴퓨터들을 묶어 대형 컴퓨터에 버금가는 시스템을 만들었는데 이를 분산 시스템(Distributed system)이라고 부른다. 분산 시스템은 네트워크 상에 분산되어 있는 여러 컴퓨터로 작업을 처리하고 그 결과를 상호 교환하도록 구성한 시스템이다. 

 

 


 

   (6) 클라이언트/서버 시스템(1990년대 ~ 현대)   

 

 분산 시스템은 모든 컴퓨터가 동일한 지위이기 때문에 컴퓨터가 고장 나거나 추가되면 작업을 분배하고 결과를 모으기가 쉽지 않다. 클라리언트/서버 시스템(Client/Server Syetem)은 이러한 문제를 해결한다. 모든 컴퓨터의 지위가 동일한 분산 시스템과 달리 작업을 요청하는 클라이언트와 거기에 응답하여 요청받은 작업을 처리하는 서버의 이중 구조로 나뉜다. 웹 시스템이 전형적인 클라이언트/서버 구조를 이루고 있다. 

 

 클라이언트/서버 시스템도 문제점이 존재한다. 바로 서버 과부하인데 수십만명의 모든 요청이 서버로 집중되면서버가 다운 될 수 있다. 

 

 

 


 

   (7) P2P 시스템(2000년대 ~ 현대)   

 

 1990년대 말에 전 세계의 MP3 음악 파일을 공유하려는 시도가 있었는데 문제는 클라이언트/서버 시스템의 서버 과부하였다. 웹 페이지는 킬로 바이트 단위이지만 MP3 파일은 메가 바이트에 달하기 때문에 서버 과부하로 서비스를 할 수 없다. 

 

 서버의 부하를 줄일 수 있는 새로운 시스템으로 P2P 시스템(Peer-to-Peer System)이 만들어졌다. peer는 말단 노드, 즉 사용자의 컴퓨터를 가르키며, P2P는 서버를 거치지 않고 사용자와 사용자를 직접 연결한다는 의미이다. P2P 시스템에는 서버가 파일 검색만 맡고 사용자 간에 파일 전송이 이루어지기에 서버의 부하가 적다는 장점이 있다. 또 다른 예로는 메신저와 파일 공유를 들 수 있다. 

 

 다음 그림은 대용량 파일 공유 P2P 시스템의 작동 방법이다. 이 시스템에서는 같은 파일을 가진 여러 사람으로부터 데이터를 나누어 받는다. 예를 들어, korea.avi라는 동영상을 받는다면 korea.avi를 가진 여러 사용자로부터 조금씩 나누어 받아 하나의 파일을 완성하는 것이다. 당연히 파일을 가지고 있는 사람이 많을수록 속도가 빨라진다. 

 

 

 

 


 

   (8) 기타 컴퓨팅 환경(2000년대 초반 ~ 현대)   

 

 ■ 그리드 컴퓨팅

       - 정해진 기간에만 컴퓨터를 사용하고 지불할 수 있도록 컴퓨팅 자원을 구매하여 사용하는 컴퓨팅 환경을 그리드 컴퓨팅

       (Grid Computing)이라고 한다. 그리드 컴퓨팅은 분산 시스템 중 한 분야로, 서로 다른 기종의 컴퓨터들을 묶어 대용량

       의 컴퓨터 풀(Computer Pool)을 구성하고 이를 원격지와 연결하여 대용량 연산을 수행하는 컴퓨팅 환경이다. 대용량

       데이터의 연산을 소규모 연산으로 나누어 여러 대의 컴퓨터로 분산 시킨다는 점에서 분산 시스템이라고 볼 수 있다. 

 

      - 그리드 시스템은 일반인을 위한 시스템이라기 보다 연구용이나 상업용으로 이용되는 시스템으로 일반인은 웹 하드 서비

      스에서 경험할 수 있다. 서버에 엄청난 양의 데이터를 보관하고 있는 웹 하드는 과부하를 방지하기 위해 P2P 시스템 기술을

      사용한다. 또한, 웹 하드 서비스는 그리드 딜리버리 기술을 이용하여 사용자 몰래 프로그램을 깔아서 서버의 부하를 방지한

      다.

 

 

 ■ 쿨라우드 컴퓨팅

      - 클라우드 컴퓨팅(Cloud Computing)은 언제 어디서나 응용 프로그램과 데이터를 자유롭게 사용할 수 있는 컴퓨팅 환경

      으로 그리드 컴퓨팅과 SaaS(필요한 기능을 모아 서버에서 실행하고 사용자는 인터넷을 통해 필요한 서비스만 제공받으며

      월별로 혹은 서비스 이용량 만큼 비용을 지불하는 방식)를 합쳐놓은 방식이다. 

 

 

 ■ 사물 인터넷

      - 사물 인터넷(Internet of Things)은 사물에 센서와 통신 기능을 내장하여 인터넷에 연결하는 기술이다. 인터넷으로 연결

      된 사물들이 데이터를 주고 받아 스스로 분석하고 학습한 정보를 사용자에게 제공하거나 서비스를 창출한다. 인공지능, 로

      봇 공학, 무인 운동 수단 등에 쓰인다. 

 

'운영체제 > 기초' 카테고리의 다른 글

6. CPU와 메모리(2)  (0) 2020.10.14
5. CPU와 메모리(1)  (0) 2020.10.06
4. 하드웨어의 기본 구성  (0) 2020.10.05
3. 운영체제의 구조  (0) 2020.10.05
1. 운영체제  (0) 2020.09.28