---
title: 클라우드 코드 단위 테스트 작성 및 실행 방법
slug: docs-kr/cloud-code-functions/unit-tests
description: 클라우드 코드 함수를 위한 Jasmine과 Parse Server 테스트 러너를 구성하고 실행하는 방법을 알아보세요.
image: https://www.back4app.com/images/logo-social.png
createdAt: 2024-02-28T13:56:55.364Z
---

# 클라우드 코드 기능을 통해 단위 테스트를 만드는 방법

## 소개

이 섹션에서는 [parse-server-test-runner](https://github.com/AmpMe/parse-server-test-runner) 라이브러리를 사용하여 로컬에서 함수의 작동 및 테스트를 확인할 수 있습니다.

## 전제 조건

:::hint{type="info"}
- 이 튜토리얼을 완료하려면 다음이 필요합니다:

- 단위 테스트를 적용하기 위해 Node.js가 설치된 로컬 환경. 터미널에서 Node.js를 성공적으로 설치하려면 [공식 NodeJS 튜토리얼](https://nodejs.org/en/download/package-manager/)을 따르세요.
- Back4App에서 생성된 앱.
- Back4App에서 앱을 만드는 방법을 배우려면 [새 앱 만들기 튜토리얼](https://www.back4app.com/docs/get-started/new-parse-app)을 따르세요.
- 프로젝트에 구성된 Back4App 명령줄.
- 프로젝트에 대한 클라우드 코드를 설정하는 방법을 배우려면 [클라우드 코드 설정 튜토리얼](https://www.back4app.com/docs/local-development/parse-cli)을 따르세요.
:::

## 우선, 단위 테스트에 대해 이야기해 보겠습니다!

개발자들이 다양한 의도를 가지고 함수를 작성하기 시작할 때, 소프트웨어 커뮤니티에서 분명한 주요 포인트는 생성된 코드를 테스트하기 위한 가상의 시나리오의 적용입니다. 단위 테스트 절차를 수행하는 것은 코드의 일부를 테스트할 수 있게 해주므로, 주요 코드가 손상되지 않고 온전하게 유지되도록 보장합니다.

### 그럼 간단한 실용적인 예는 어떨까요?

완전한 문장으로 작업자의 이름, 직위 및 회사를 보여주는 함수를 작성해야 한다고 가정해 보겠습니다. 다음 입력 항목을 가져오기 위해 함수를 작성해야 합니다:

- 회사
- 직위
- 작업자 이름

## 간단한 테스트를 완료하는 단계

터미널에서 먼저 디렉토리를 만들고 테스트 앱(package.json)을 구성하겠습니다. 다음 명령어를 사용하세요:

:::BlockQuote
$ mkdir unit-test-sample && cd unit-test-sample
$ npm init
:::

:::hint{type="warning"}
힌트: <font color="#2166ae">`npm init`</font> 명령어를 사용하면 package.json 파일을 생성할 수 있습니다. 이 명령어는 가장 일반적인 항목만 포함하고 합리적인 기본값을 추측하려고 합니다. 이 때문에 코드가 작동하는 데 필요한 종속성을 제공할 것입니다.
:::

“package.json”의 결과는 아래 예와 비슷할 것입니다:

```json
{
  "name": "yourfoldername",
  "version": "1.0.0",
  "description": "Just a unit test with using a simple function.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": ""
  },
  "author": "Your Name",
  "license": "ISC",
  "bugs": {
    "url": "{url}/issues"
  },
  "homepage": ""
}
```

이제 아래 명령어를 사용하여 파일(index.js)을 생성해 보겠습니다:

:::BlockQuote
\~/unit-test-sample$ touch index.js
:::

이제 이전에 생성한 파일에 아래 코드를 삽입할 것이며, 이 함수는 이 테스트를 코드로 보여줄 수 있는 예제를 삽입할 것입니다:

```javascript
1   // index.js
2     module.exports = function(name, position, company) {
3     let sentence = "Hi, " + name + "! You are " + position + " in " + company + " company.";
4       return sentence;
5     };
```

:::hint{type="info"}
**NodeJS에서 모듈은 관련 코드를 단일 코드 단위로 캡슐화하며, *module.exports*,를 사용하면 다른 파일에서 활용할 수 있는 캡슐화된 코드가 증가합니다.**
:::

### 0/ 테스트해 보겠습니다.

마지막으로, 터미널에서 작업할 수 있습니다:

:::BlockQuote
\~/unit-test-sample$ node
\> var moduleBack4App = require('./index.js');
undefined
\> moduleBack4App("Jonathan", "Developer", "Back4App")
안녕하세요, Jonathan! 당신은 Developer로 Back4App 회사에 있습니다.
:::

:::hint{type="warning"}
힌트:&#x20;<font color="#2166ae">`require()`</font> 함수를 사용하면 모듈을 가져오고 내보낼 수 있으며, 위의 경우에는 이 함수를 사용하여 애플리케이션 내에서 파일을 요구하고 있습니다.
:::

# Parse를 사용하여 내 함수를 테스트할 수 있나요?

물론입니다. 테스트 매개변수로 회사 직원의 정보를 제어하는 백엔드를 생성할 것입니다.

# 클래스를 다음과 같이 구조화해 보겠습니다:

### Parse.User (직원 참조)

- 사용자 이름, 이메일, 비밀번호 (필수)

User 속성에 대한 추가 정보를 얻으려면 [Parse Server](http://docs.parseplatform.org/js/guide/#users) 가이드를 자세히 살펴보는 것을 권장합니다.

### infoEmployee

- 직위
- 부서
- 근무 교대
- userId (포인터)

## 1 - 우리의 최종 구조 이해하기

시작해봅시다! 우리는 [Parse Server 자바스크립트 가이드](https://www.back4app.com/docs/cloud-code-functions/docs.parseplatform.org/js/guide/)를 함수 개발의 매개변수로 사용할 것입니다. 먼저, Command Line Interface를 사용하여 설정을 완료한 후 [(사전 요구 사항을 참조하세요](https://www.back4app.com/docs/cloud-code-functions/unit-tests#content-prerequisites)), 우리는 파일의 최종 구조와 함께 어떻게 작동하는지 이해할 것입니다:

:::BlockQuote
├──Back4AppProject
│  ├── cloud
│  │   ├── functions.js
│  │   ├── main.js
│  ├── public
│  ├── package.json
│  ├── index.js
│  ├── node\_modules
│  ├── src
│  │   ├── jasmine.js
:::

:::hint{type="info"}
**알림:&#x20;**&#x43;loud Code에 파일을 업로드할 때, Command Line Interface(참조 [사전 요구 사항](https://www.back4app.com/docs/cloud-code-functions/unit-tests#content-prerequisites))는 다른 파일을 무시하고 public 및 cloud 폴더에 있는 파일만 업로드합니다.
:::

## 2 - 함수 작성하기

Command Line Interface를 위한 환경을 구성한 후, 우리는 직원 등록 프로세스를 구축하고 추가 정보를 저장하기 위한 함수를 작성할 것입니다. 코드를 리팩토링하여 main.js 파일에서 이러한 함수를 main에 가져올 것입니다, 다음과 같이:

```javascript
1   //In 1cloud/main.js
2
3   var cloudFunctions = require("./functions");
4
5   /* It's necessary to insert the Parse Instance in our code,
6   because at local context not is referenced.*/
7
8   Parse.Cloud.define("registerUser",  cloudFunctions.registerUser(Parse));
9
10  Parse.Cloud.beforeSave("infoEmployee", infoEmployee.infoEmployee(Parse));
```

아이디어는 클라우드 인터페이스에서 기능을 분리하여 HTTP 요청을 비효율적으로 보내지 않고도 테스트할 수 있도록 하는 것입니다. 이는 테스트 스위트를 만들면서 많은 의미가 있을 것입니다.

:::CodeblockTabs
Parse Server 3.X

```javascript
1   //In cloud/functions.js
2
3   module.exports.registerUser = function(Parse){
4     return async(request) =>{
5       let params = request.params; //Parameters received  
6       let infoEmployee = Parse.Object.extend("infoEmployee"); //Store Information      
7
8       let userCreated = new Parse.User({
9         "email" : params.email,
10        "username": params.username,
11        "password" : params.password
12      })
13
14      //Save relation
15      try {
16        let result = await userCreated.save();
17
18        let information = new infoEmployee({
19          "position"   : params.position,
20          "department" : params.department,
21          "workShift"  : params.shift,
22          "user" : result
23        });
24
25        return information.save();
26      } catch (e) {
27          return e.message;
28      }
29    }
30  }
31
32  module.exports.infoEmployee = function(Parse){
33    return async (request) =>{
34      let req = request.object;
35
36      if (!req.get("position") || !req.get("department") || !req.get("workShift")) {
37        throw new Error("Missing params! The required parameters are: position, department. workShift");
38      } else {
39        return;
40      }
41    }
42  }
```

Parse Server 2.X

```javascript
1   //In cloud/functions.js
2
3   module.exports.registerUser = function(Parse){
4     return function (request, response){
5       var params = request.params; //Parameters received
6
7       var infoEmployee = Parse.Object.extend("infoEmployee"); //Store Information      
8
9       var userCreated = new Parse.User({
10        "email" : params.email,
11        "username": params.username,
12        "password" : params.password
13      })
14
15      //Save relation
16      userCreated.save().then((updatedUser) => {
17        var information = new infoEmployee({
18          "position"   : params.position,
19          "department" : params.department,
20          "workShift"  : params.shift,
21          "user" : updatedUser
22        });
23        return information.save();
24      }).then((info) => response.success(info))
25        .catch((e) => {
26          response.error(e.message);
27        })
28    }
29  }
30
31  module.exports.infoEmployee = function(Parse){
32    return function (request, response){
33      var req = request.object;
34
35      if (!req.get("position") || !req.get("department") || !req.get("workShift")) {
36        response.error("Missing params! The required parameters are: position, department. workShift");
37      } else {
38        response.success();
39      }
40    }
41  }
```
:::

## &#x20;3 - 위 코드를 테스트하기 위한 환경 설정!

우리의 테스트 스위트에서는 [Jasmine](https://jasmine.github.io/), 매우 인기 있는 JavaScript 테스트 프레임워크를 사용할 것입니다. 그러나 지금까지의 코드는 우리의 테스트와 완전히 무관하므로, 원하는 프레임워크나 플랫폼을 사용할 수 있습니다.

### 개발 종속성 설치

Jasmine을 전역적으로 설치하고 아래 명령어를 사용합시다:

:::BlockQuote
\~/Back4AppProject$ sudo npm install -g jasmine
\~/Back4AppProject$ jasmine
시드 48094로 무작위화됨
시작됨


사양을 찾을 수 없음
0.002초 만에 완료됨
불완전: 사양을 찾을 수 없음
:::

## 4 - 폴더에서 Parse Server 테스트 러너 구성하기

Back4App의 프로젝트 클라우드 폴더에 구현된 우리의 방법을 사용하여, 이 상호작용을 구성할 Node.js 프로젝트에 새로운 파일을 생성할 것입니다.

:::BlockQuote
\~/Back4AppProjectsrc$ touch index.js
\~/Back4AppProject$ mkdir src && cd src
\~/Back4AppProject/src$ touch jasmine.js
:::

이제 위에서 생성한 파일을 아래에 표시된 코드로 구성하겠습니다:

:::CodeblockTabs
index.js

```javascript
1   const Promise = require('bluebird');
2     const express = require('express');
3     const http = require('http');
4     const {MongoClient} = require('mongodb');
5     const {ParseServer} = require('parse-server');
6
7     const mongoDBRunnerStart = require('mongodb-runner/mocha/before').bind({
8      timeout() {
9       },
10      slow() {
11      },
12    });
13    const mongoDBRunnerStop = require('mongodb-runner/mocha/after');
14
15    const startDB = () => (
16      new Promise((done, reject) => {
17        done.fail = reject;
18        mongoDBRunnerStart(done);
19      })
20    );
21
22    const stopDB = () => (
23      new Promise((done, reject) => {
24        done.fail = reject;
25        mongoDBRunnerStop(done);
26      })
27    );
28
29    const connectDB = (databaseURI) => new Promise((resolve, reject) => {
30      MongoClient.connect(databaseURI, (err, db) => {
31        if (err) {
32          reject(err);
33        } else {
34          resolve(db);
35        }
36      });
37    });
38
39    let parseServerState = {};
40
41    const dropDB = () => {
42      const {mongoConnection} = parseServerState;
43      return mongoConnection.dropDatabaseAsync();
44    };
45
46    /**
47      * Starts the ParseServer idropDatabaseAsyncnstance
48      * @param {Object} parseServerOptions Used for creating the `ParseServer`
49      * @return {Promise} Runner state
50     */
51    function startParseServer(parseServerOptions = {}) {
52      const mongodbPort = process.env.MONGODB_PORT || 27017;
53      const {
54        databaseName = 'parse-test',
55        databaseURI = 'mongodb://localhost:${mongodbPort}/${databaseName}',
56        masterKey = 'test',
57        javascriptKey = 'test',
58        appId = 'test',
59
60        port = 30001,
61        mountPath = '/1',
62        serverURL = 'http://localhost:${port}${mountPath}',
63      } = parseServerOptions;
64
65      return startDB()
66        .then(() => connectDB(databaseURI))
67        .then((mongoConnection) => {
68         parseServerOptions = Object.assign({
69            masterKey, javascriptKey, appId,
70            serverURL,
71            databaseURI,
72            silent: process.env.VERBOSE !== '1',
73          }, parseServerOptions);
74          const app = express();
75          const parseServer = new ParseServer(parseServerOptions);
76
77          app.use(mountPath, parseServer);
78
79          const httpServer = http.createServer(app);
80
81          Promise.promisifyAll(httpServer);
82          Promise.promisifyAll(mongoConnection);
83
84          return httpServer.listenAsync(port)
85            .then(() => Object.assign(parseServerState, {
86              parseServer,
87              httpServer,
88              mongoConnection,
89              expressApp: app,
90              parseServerOptions,
91            }));
92        });
93    }
94
95  /**
96   * Stops the ParseServer instance
97   * @return {Promise}
98   */
99    function stopParseServer() {
100     const {httpServer} = parseServerState;
101     return httpServer.closeAsync()
102       .then(stopDB)
103       .then(() => parseServerState = {});
104   }
105 
106   module.exports = {
107     dropDB,
108     startParseServer,
109     stopParseServer,
110     parseServerState,
111   };
```

jasmine.js

```javascript
1   const { startParseServer, stopParseServer, dropDB } = require('parse-server-test-runner');
2
3   describe('registerUser', () => {
4      beforeAll((done) => {
5       const appId = 'test';
6       const masterKey = 'test';
7       const javascriptKey = 'test';
8
9       startParseServer({ appId, masterKey, javascriptKey })
10        .then(() => {
11          Parse.initialize(appId, masterKey, javascriptKey);
12          Parse.serverURL = 'http://localhost:30001/1';
13        })
14        .then(done).catch(done.fail);
15    }, 300 * 60 * 2);
16
17    afterAll((done) => {
18      stopParseServer()
19        .then(done).catch(done.fail);
20    });
21
22    beforeEach((done) => {
23      dropDB()
24        .then(done).catch(done.fail);
25    });
26
27    it('should work', (done) => {
28      const q = new Parse.Query('_User')
29      q.limit(5)
30        .find({ useMasterKey: true })
31        .then(console.log)
32        .then(done).catch(done.fail);
33    });
34  });
```
:::

마지막 단계는 다음 명령어를 사용하여 package.json을 구성하는 것입니다: <font color="#2166ae">`$ npm init`</font> 루트 디렉토리에서 (아래 파일은 필요한 모듈의 예일 뿐입니다):

```json
1   {
2     "name": "back4approject",
3     "version": "1.0.0",
4     "description": "Back4App guide using for reference the Parse Server Test Runner",
5     "main": "index.js",
6     "engines": {
7       "node": ">=6"
8     },
9     "repository": {
10      "type": "",
11      "url": ""
12    },
13    "keywords": [
14      "parse",
15      "parse-server",
16      "testing",
17      "tests"
18    ],
19    "author": "",
20    "license": "ISC",
21    "dependencies": {
22      "bluebird": "^3.5.0",
23      "express": "latest",
24      "mongodb": "^2.2.30",
25      "mongodb-runner": "^3.5.0",
26      "parse": "^1.10.0",
27      "parse-server": "^2.5.3",
28      "parse-server-test-runner": "^1.0.0"
29    }
30  }
```

이제 우리는 [이전의](https://www.back4app.com/docs/cloud-code-functions/unit-tests#content-structure) 단계에서 설명한 구조에 접근했는지 확인할 것입니다 :)

## 5 - 터미널로 돌아가기

로컬 테스트를 구성하기 시작하겠습니다. 이를 위해 아래 명령어를 따라 코드를 프로그래밍 방식으로 설정하여 테스트 목적으로 사용할 것입니다.

:::BlockQuote
\~/Back4AppProject$ # package.json이 있는 동일한 디렉토리에서
\~/Back4AppProject$ npm install
:::

성공적으로 설치한 후, 설명된 명령어로 로컬에서 단위 테스트를 확인하고 다음과 같은 결과를 받을 수 있습니다:

:::BlockQuote
\~/Back4AppProject$ jasmine src/jasmine.js
시드 79055로 무작위화됨
시작됨
✔  MongoDB 3.6.5 다운로드됨
\[]
.


1 스펙, 0 실패
19.983초 만에 완료됨
시드 79055로 무작위화됨 (jasmine --random=true --seed=79055)
:::




## 멋져요, 준비 완료!

위에 설명된 가이드를 통해 Parse Server Test Runner와 Back4App을 위한 Cloud Code로 개발한 함수와 함께 작업할 수 있습니다.
