Advanced Guides
Back4App에서 Parse Cloud Code 테스트 통합을 위한 가이드
32 분
테스트를 parse cloud code 함수에 통합하는 방법 소개 이 가이드는 https //github com/considine , 우리의 게스트 작가이자 https //koptional com/ ,의 수석 개발자가 작성했습니다 이 튜토리얼은 back4app cloud code에 대한 자동화된 테스트 설정 방법을 다룹니다 클라이언트 parse 코드를 클라우드로 이동하는 방법과 프로젝트를 테스트 생태계와 통합하는 방법에 대해 간단히 이야기하겠습니다 또한 예제 프로젝트 https //github com/back4app/template cloud code unit test 을 직접 확인하여 작동하는 버전을 확인할 수 있습니다 목표 우리는 자동화된 테스트의 강력하고 확장 가능한 측면을 개발자 친화적인 parse 환경과 결합하기를 희망합니다 cloud code를 활용함으로써, 아마도 parse의 과소평가된 기능인 이 기능을 통해 개발자들은 코드를 신속하게 반복할 수 있으며 소프트웨어가 예상대로 실행될 것이라는 확신을 가질 수 있습니다 테스트 주도 개발 https //en wikipedia org/wiki/test driven development 은 방대한 분야입니다; 테스트에 대해 철학적으로 이야기하기보다는 구현을 통해 몇 가지 전략(예 스텁)에 대해 이야기하겠습니다 전제 조건 이 튜토리얼을 완료하려면 다음이 필요합니다 back4app에 앱이 있어야 합니다 다음 튜토리얼을 따르세요 새 앱 만들기 튜토리얼 back4app에서 앱을 만드는 방법을 배우세요 프로젝트에 구성된 back4app 명령줄 다음 튜토리얼을 따르세요 클라우드 코드 설정 튜토리얼 프로젝트에 대한 클라우드 코드를 설정하는 방법을 배우세요 명령줄에 npm이 설치되어 있어야 합니다 참고 이 라이브러리는 https //www promisejs org/ , 이는 그리 복잡하지 않을 것입니다 기본 소셜 미디어 백엔드를 만들어 봅시다 좋아요! 사용자 모델과 함께 프로필 모델을 포함하는 소셜 미디어 애플리케이션을 상상해 보세요 일부 앱의 경우 프로필 정보를 사용자 모델에 포함할 수 있지만, 많은 경우 이는 비효율적입니다 권한 부여/인증과 사용자 콘텐츠의 문제를 분리해야 하므로 두 개의 다른 모델을 유지해야 합니다 이 튜토리얼에서는 사용자의 생성과 프로필 관리를 최소한의 클라이언트 부담으로 구현하는 기능을 구현할 것입니다 시작해 봅시다! 1\ 함수 정의하기 이것은 back4app 프로젝트가 생성되어 있고, 명령줄 도구가 설치되어 있다고 가정합니다 (필수 조건 참조) 프론트엔드 코드의 예를 위해, 이 가이드는 단순성을 위해 parse javascript sdk 구문을 참조할 것입니다 누군가 이 애플리케이션에 가입할 때, 프로필이 생성되어 사용자 객체와 연결되어야 합니다 가입 함수 많은 parse 애플리케이션에서 다음 구문을 사용하여 사용자를 생성합니다 1 var user = new parse user(); 2 user set("username", "my name"); 3 user set("password", "my pass"); 4 user set("email", "email\@example com"); 우리의 경우, 프로필을 초기화하고 이를 사용자 객체에 연결하고자 합니다 parse server 3 x 1 try { 2 await user signup(null, {usemasterkey true}); 3 let profile = parse object extend("profile"); 4 let profile = new profile({ 5 firstname params firstname, 6 lastname params lastname, 7 user user 8 }) 9 return profile save(null, {usemasterkey true}); 10 } catch (err){ 11 return (err message); 12 } parse server 2 x 1 user signup(null, { 2 success function (newuser) { 3 var profile = parse object extend("profile"); 4 var profile = new profile(); 5 profile set("firstname", "john"); 6 profile set("lastname", "smith"); 7 profile set("user", newuser); 8 profile save(); 9 }, 10 error function (err) { 11 // handle error 12 } 13 }) 이 구문을 다음과 같이 간단하게 줄일 수 있습니다 parse server 3 x 1 let user = new parse user({ 2 username params username, 3 password params password, 4 email params email 5 }); 6 7 try { 8 await user signup(null, {usemasterkey true}); 9 let profile = parse object extend("profile"); 10 let profile = new profile({ 11 firstname params firstname, 12 lastname params lastname, 13 user user 14 }) 15 return profile save(null, {usemasterkey true}); 16 } catch (err){ 17 return (err message); 18 } parse server 2 x 1 var user = new parse user({ 2 username params username, 3 password params password, 4 email params email 5 }); 6 user signup(null) 7 then((newuser) => { 8 var profile = parse object extend("profile"); 9 var profile = new profile({ 10 "firstname" "john", 11 "lastname" "smith", 12 "user" newuser 13 }); 14 return profile save(); 15 }) 불행히도, 이것은 여전히 parse server에 두 개의 별도의 요청을 보내는 것을 포함하며, 이는 프론트엔드에서 수행하기에는 비효율적입니다 가능하면 여러 단계의 클라이언트 서버 통신 흐름을 피하는 것이 현명합니다 또한 보안과 관련하여, 위의 코드는 생성 프로세스를 클라이언트의 손에 맡기고 있으며, 이는 결코 현명하지 않습니다 우리는 데이터 무결성이 클라이언트가 흐름의 모든 단계를 제대로 완료하는 것에 의존하는 것을 방지하고 싶습니다 예를 들어, 프로필 없이 사용자를 생성하는 사용자 정의 요청을 보낼 수 있어 앱의 지속적인 데이터가 손상될 수 있습니다 클라우드 코드를 사용하여 모든 작업을 한 번에 수행하는 것이 어떻습니까? 이는 프론트엔드 코드의 부풀어 오르는 것을 방지하고, 클라이언트가 불필요하거나 안전하지 않은 작업을 수행하지 않도록 보장할 수 있습니다! 회원가입을 위해 클라이언트에서 대신 하고 싶은 것은 다음과 같습니다 1 parse cloud run('signupuser', 2 { 3 username 'myname', 4 password "mypass", 5 email "email\@example com", 6 firstname "john", 7 lastname "smith" } 8 ) then(function(newuser) { 9 10 }); parse는 또한 http //docs parseplatform org/cloudcode/guide/#beforesave triggers 트리거를 정의하여 사용자가 가입할 때 프로필을 생성할 수 있도록 합니다 그러나 함수를 사용하여 프로필이 사용할 firstname 및 lastname 속성을 직관적으로 전달할 수 있습니다 클라우드 코드 가입 함수 시작해봅시다! back4app과 동기화된 프로젝트 디렉토리로 이동하세요 (이게 무슨 뜻인지 모른다면 사전 요구 사항을 참조하세요) 다음 구조를 가정하겠습니다 우리의 경우 초기화 시 ‘cloud’를 디렉토리 이름으로 선택했습니다 당신의 디렉토리는 원하는 대로 이름을 지을 수 있습니다 parse server 3 x main js 1 parse cloud define("signuserup", async(request) => { 2 // make sure the necessary parameters are passed first 3 let params = request params; 4 if (!params username || !params email || !params password || !params firstname || !params lastname) 5 throw new error("missing parameters need username, email, password, firstname, & lastname"); 6 7 // execute the signup flow 8 let user = new parse user({ 9 username params username, 10 password params password, 11 email params email 12 }); 13 14 try { 15 await user signup(null, {usemasterkey true}); 16 let profile = parse object extend("profile"); 17 let profile = new profile({ 18 firstname params firstname, 19 lastname params lastname, 20 user user 21 }) 22 return profile save(null, {usemasterkey true}); 23 } catch (err){ 24 return (err message); 25 } 26 }); parse server 2 x main js 1 parse cloud define("signuserup", function(request, response) { 2 // make sure the necessary parameters are passed first 3 var params = request params; 4 if (!params username || !params email || !params password || !params firstname || !params lastname) 5 return response error("missing parameters need username, email, password, firstname, & lastname"); 6 7 // execute the signup flow 8 var user = new parse user({ 9 username params username, 10 password params password, 11 email params email 12 }); 13 user signup(null, {usemasterkey true}) 14 then((newuser) => { 15 var profile = parse object extend("profile"); 16 var profile = new profile({ 17 firstname params firstname, 18 lastname params lastname, 19 user newuser 20 }) 21 return profile save(null, {usemasterkey true}); 22 }) 23 then((prof) => response success(prof)) 24 catch((e) => { 25 response error(e message); 26 }) 27 }); ‘usemasterkey’ 옵션이 전달되는 것을 주목할 수 있습니다 이는 클라우드 코드가 설정된 역할이나 acl을 초월할 수 있게 해줍니다 클라이언트가 이 코드를 건드리지 않기 때문에 서버를 탈취할 위험이 없습니다 그러나 이 플래그를 사용할 때는 주의하세요! 이 기능을 클라이언트 코드에 배치하는 것보다 이 방법이 더 바람직한 이유가 명확하지 않다면, 다음과 같은 장점이 있습니다 장치가 아닌 서버에 계산을 오프로드합니다 프로세스의 기능을 명시적으로 정의합니다 안전 장치 기능을 더 쉽게 생성할 수 있습니다 클라이언트에게 직관적인 인터페이스를 제공합니다 이것은 클라이언트가 프로세스를 ‘반만’ 수행할 가능성을 방지합니다 2\ 디렉토리 구조 리팩토링 좋습니다, 우리는 두 개의 클라우드 기능을 만들었습니다 우리는 이러한 기능을 실행하고 parse 대시보드를 확인하여 테스트할 수 있지만, 이는 확장 가능하거나 효율적이지 않습니다 대신 우리는 지속적으로 실행할 수 있는 메서드에 대해 자동화된 테스트를 만들고자 합니다 그래서 우리는 코드를 조금 분리할 것입니다 우리는 main js에서 만든 기능을 cloud functions js라는 새 파일로 이동할 것입니다(같은 디렉토리 내에서) 그런 다음 우리는 import 이 기능을 main으로 가져오고, 클라우드 기능 정의에 바인딩할 것입니다 아이디어는 decouple 기능을 클라우드 인터페이스에서 분리하여 비효율적으로 http 요청을 보내지 않고도 테스트할 수 있도록 하는 것입니다 이는 테스트 스위트를 만들 때 많은 의미가 있을 것입니다 기능 파일 생성 node js에서 다른 파일에서 함수, 객체 및 변수를 가져오기 위해 'require'를 사용할 수 있다는 것을 알고 계실 것입니다 따라서 우리는 1단계에서 만든 parse 클라우드 기능에 해당하는 함수를 정의할 것입니다 하나의 혼란스러운 점은 우리가 정의하는 함수가 returning functions , 즉 parse 클라우드 정의에 연결될 수 있는 함수라는 것입니다 함수를 사용하여 함수를 반환하는 것이 이상하게 보일 수 있지만, 이는 나중에 테스트를 작성할 때 parse 서버를 교체할 수 있는 힘을 제공합니다 cloud code에서 parse 객체를 정의하거나 가져오지 않고도 사용할 수 있다는 것을 눈치채셨을 것입니다 이는 이 코드를 실행하는 서버가 parse를 자동으로 추가하기 때문입니다 그러나 로컬에서 함수에 대한 테스트를 실행하려면 인스턴스가 제공되지 않습니다 사실, 우리는 데이터가 생성되거나 삭제되는 데 해가 없는 테스트 parse 서버에 해당하는 인스턴스를 제공하고자 합니다 각 함수는 ‘parse’를 매개변수로 받아들이고, 클라우드 함수를 반환합니다 parse server 3 x cloud functions js 1 // cloud functions js 2 module exports signupuser = function(parse) { 3 return async(request) => { 4 // copied from main js 5 // make sure the necessary parameters are passed first 6 let params = request params; 7 if (!params username || !params email || !params password || !params firstname || !params lastname) 8 throw new error("missing parameters need username, email, password, firstname, & lastname"); 9 10 // execute the signup flow 11 let user = new parse user({ 12 username params username, 13 password params password, 14 email params email 15 }); 16 17 try { 18 await user signup(null, {usemasterkey true}); 19 let profile = parse object extend("profile"); 20 let profile = new profile({ 21 firstname params firstname, 22 lastname params lastname, 23 user user 24 }) 25 return profile save(null, {usemasterkey true}); 26 } catch (err){ 27 return (err message); 28 } 29 } 30 } parse server 2 x cloud functions js 1 // cloud functions js 2 module exports signupuser = function(parse) { 3 return function (request, response) { 4 // copied from main js 5 // make sure the necessary parameters are passed first 6 var params = request params; 7 if (!params username || !params email || !params password || !params firstname || !params lastname) 8 return response error("missing parameters need username, email, password, firstname, & lastname"); 9 // execute the signup flow 10 var user = new parse user({ 11 username params username, 12 password params password, 13 email params email 14 }); 15 user signup(null, {usemasterkey true}) 16 then((newuser) => { 17 var profile = parse object extend("profile"); 18 var profile = new profile({ 19 firstname params firstname, 20 lastname params lastname, 21 user newuser 22 }) 23 return profile save(null, {usemasterkey true}); 24 }) 25 then((prof) => response success(prof)) 26 catch((e) => { 27 response error(e message); 28 }) 29 } 30 } main js에서 모든 것을 제거합니다 클라우드 함수를 가져오고, 다음과 같이 클라우드 함수 정의에 함수를 바인딩합니다 1 // main js 2 var cloudfunctions = require(" /cloud functions"); 3 // note that we are injecting the parse instance, which is automatically supplied in the 4 // context of parse cloud code, but not on local tests 5 parse cloud define("signuserup", cloudfunctions signupuser(parse)); 좋습니다! 1단계 이후로 기능은 전혀 변경되지 않았지만, 클라우드 코드에서 함수를 분리했습니다 다음 단계에서는 단위 테스트를 생성할 것입니다! 3\ 테스트 스위트 만들기 우리의 테스트 스위트에는 jasmine https //jasmine github io/ , 인기 있는 테스트 프레임워크를 사용할 것입니다 그러나 지금까지 우리의 코드는 테스트와 완전히 무관하므로, 원하는 프레임워크나 플랫폼을 사용하셔도 됩니다 jasmine과 jasmine node( jasmine과 우리의 node js 환경의 통합)를 설치해 봅시다 이제 테스트 스위트에서 사용할 두 개의 라이브러리를 설치하겠습니다 가짜 parse 서버에 연결하기 위해 parse sdk를 사용하고, 요청 객체를 스텁하기 위해 events 라이브러리를 사용할 것입니다 이제 jasmine 유틸리티를 사용하여 테스트 디렉토리를 초기화하겠습니다 원하신다면, $ npm install g jasmine $ npm install g jasmine 로 jasmine을 전역으로 설치할 수 있습니다 그러면 다음과 같이 초기화할 수 있습니다 $ jasmine init $ jasmine init 이 가이드는 jasmine을 전역으로 설치하지 않는다고 가정하지만, 설치하는 것이 권장됩니다 설치하는 경우 ‘/node modules/jasmine/bin/jasmine js’의 모든 인스턴스를 단순히 ‘jasmine’으로 교체할 수 있습니다 이렇게 하면 spec이라는 디렉토리가 생성되며, 그 안에는 jasmine의 구성 정보를 포함하는 support 폴더가 포함됩니다 기본적으로 jasmine은 “ spec js” 확장자로 끝나는 파일을 찾도록 알고 있으므로, 테스트 이름을 그에 맞게 지정하겠습니다 첫 번째 단위 테스트를 위한 파일을 생성합니다 테스트에 도움이 될 두 개의 파일이 있는 utilities 디렉토리를 추가합니다 마지막으로, 같은 디렉토리에 상수 파일을 생성합니다 이 파일의 유틸리티는 나중에 설명하겠습니다 이제 디렉토리가 다음과 같아야 합니다 4\ 테스트 parse 서버 교체하기 parse 주위에서 테스트하기 우리의 메서드가 parse 서버를 포함하므로, 그 상호작용을 테스트할 수 있어야 합니다 이를 수행하는 두 가지 방법이 있습니다 a 우리는 동일한 인터페이스를 구현하는 객체를 정의하여 parse sdk 객체를 "스텁"할 수 있습니다 그런 다음 그 객체를 클라우드 메서드의 매개변수로 전달하면 됩니다 그것은 다음과 같이 보일 수 있습니다 1 var parsestub = { 2 // make sure all used methods and properties are defined 3 user function () { 4 // constructor function 5 this set = function (key, val) { 6 // logic here to implement the parse object set 7 } 8 } 9 } 10 signupuser(parsestub); // returns cloud function that we can test b 또 다른 접근 방식은 테스트 데이터만 제공하는 실제 parse 서버를 설정하는 것입니다 이는 parse가 사용하는 느린 http 계층을 포함하지만, 데이터베이스의 데이터를 테스트할 수 있게 해줍니다 우리의 테스트에서는 parse sdk를 가져오고, 테스트 서버로 구성해야 합니다 클라우드 코드를 테스트할 때 스텁할 수 있는 두 가지 장소 a ) http 요청을 하지 않는 parse sdk를 스텁하거나, b ) 테스트 데이터베이스 구현으로 교체하기 이 두 가지 접근 방식 중 어느 것도 "정답"이 아닙니다 무엇을 테스트하려고 하는지에 따라 다릅니다 parse sdk의 인터페이스를 스텁하는 것은 (우리가 사용하는 부분만이라도) 많은 작업이 필요합니다 또한, 이 예제에서는 저장 후 데이터의 지속성을 테스트할 것이므로 두 번째 접근 방식을 사용할 것입니다 하자 back4app에서 테스트 parse 서버를 생성합니다 애플리케이션 id와 마스터 키를 가져와서 상수 파일에 저장합니다 테스트 서버를 사용하도록 사양 파일에서 parse sdk를 초기화합니다 테스트를 위해 로컬 parse server https //github com/parse community/parse server 를 실행할 수 있습니다 우리는 대시보드에서 또 다른 back4app 애플리케이션을 간단히 생성할 것입니다 다른 back4app 서버를 프로비저닝하는 방법에 대한 복습이 필요하다면, 새 앱 만들기 튜토리얼 https //www back4app com/docs/get started/new parse app 을 확인하세요 애플리케이션 이름은 원하는 대로 지정할 수 있지만, testbackend와 같은 이름을 사용하는 것이 좋습니다 그런 다음 대시보드 > 앱 설정 > 보안 및 키에서 애플리케이션 id와 마스터 키를 가져오세요 이 토큰을 상수 파일에 다음과 같이 저장하세요 1 // /spec/constants js 2 // paste in your app id and master key where the strings are 3 module exports = { 4 application id "paste your application key here", 5 master key "paste your master key here" 6 } 생산 앱의 애플리케이션 id와 마스터 키를 절대 입력하지 마세요!!! 우리는 데이터를 삭제할 것이며, 그렇게 하면 데이터 손실 위험이 있습니다 5\ 테스트 유틸리티 클라우드 함수는 express 요청 및 응답 객체의 매개변수로 전달됩니다 서버는 클라우드에서 실행될 때 이러한 매개변수를 자동으로 생성하므로, 테스트 환경에서는 더블을 생성해야 합니다 이 경우는 더 쉽습니다 클라우드 함수가 호출될 때 데이터가 전달되며, 우리의 경우 프로필과 사용자 정보가 전달됩니다 제공된 모든 인수는 request params 속성에서 접근할 수 있습니다 따라서 클라우드 함수를 다음과 같이 호출하면 1 // client code, calling parse function 2 parse cloud run('fakefunction', 3 { 4 data1 'i am data1', 5 data2 { 6 prop "nested property" 7 } 8 } 9 ); 그럼 request params 속성에는 전달된 데이터가 포함됩니다 1 // server code, running the parse function 2 console log(request params); 3 // { 4 // data1 'i am data1', 5 // data2 { 6 // prop "nested property" 7 // } 8 // } 간단하게, 우리의 테스트를 위해 클라우드 함수를 호출할 때 첫 번째 인자는 다음 형식이어야 합니다 1 { 2 params { 3 username 'testuser', 4 firstname "john", 5 // the rest of the arguments 6 } 7 } 따라서 이 경우 특별한 모의 객체를 만들 필요가 없습니다 응답 객체는 클라우드 코드가 클라이언트에 성공 또는 실패를 나타내는 http 응답을 보낼 수 있도록 합니다 클라우드 기능을 호출할 때 무엇이라고 하는지 알고 싶습니다 아래는 모의 객체 https //msdn microsoft com/en us/library/ff650441 aspx 로, 우리의 테스트가 호출이 성공했는지 여부를 판단할 수 있게 해줍니다 이것이 혼란스럽다면 걱정하지 마세요, 그냥 /spec/utils/response stub js 파일에 넣어두세요 1 // /spec/utils/response stub js 2 const eventemitter = require('events'); 3 / 4 wrapper around response stub simplifies testing cloud functions that 5 employ a response parameter 6 / 7 function responsestub () { 8 this responselistener = new eventemitter(); 9 this responsestub = {}; 10 / 11 success method that cloud functions expect 12 / 13 this responsestub success = (resp) => { 14 this responselistener emit("success", resp); 15 } 16 / 17 error method that cloud functions expect 18 / 19 this responsestub error = (resp) => { 20 this responselistener emit("error", resp); 21 } 22 / 23 listens for errors and successes from stub and returns promise that resolves or rejects accordingly 24 / 25 this resolver = new promise((resolve, reject) => { 26 this responselistener on("success", (resp) => resolve(resp)); 27 this responselistener on("error", (err) => reject(err)); 28 }); 29 } 30 31 / 32 reeturns stub to feed to cloud function 33 / 34 responsestub prototype getstub = function () { 35 return this responsestub; 36 } 37 38 / 39 returns promise that will indicate the success or failure 40 / 41 responsestub prototype oncomplete = function () { 42 return this resolver; 43 } 44 45 module exports = responsestub; 간단히 말해, 이 자바스크립트 생성자 함수는 우리의 테스트가 응답 객체를 전달할 수 있는 방법을 제공하며, 이는 promise 해결/거부에 의해 클라우드 기능이 성공 또는 오류를 반환했는지를 나타냅니다 데이터베이스 정리 우리는 명백히 테스트 중에 축적된 내용을 테스트 parse 데이터베이스가 보유하기를 원하지 않습니다 테스트 케이스 전에(또는 후에) 호출할 수 있는 데이터베이스 테이블을 지우기 위한 유틸리티를 정의합시다 다음 내용을 ‘spec/utils/purge parse table js’에 추가하세요 1 // spec/utils/purge parse table js 2 / 3 removes all rows from the parse database 4 @param {string} tablename the name of the parse table to be purged 5 @return {promise} promise to destroy each item in the table 6 / 7 module exports = function (parse) { 8 return (tablename) => { 9 var tablequery; 10 if (tablename === "user") 11 tablequery = new parse query(parse user); 12 else tablequery = new parse query(tablename); 13 return tablequery find({usemasterkey true}) then((items) => { 14 var destroyqueue = \[]; 15 for (var i=0; i\<items length; i++) { 16 destroyqueue push(items\[i] destroy({usemasterkey true})); 17 } 18 return promise all(destroyqueue) catch((e) => {console log("error destroying " + e message)}); 19 }); 20 } 21 } 이 함수를 정의한 후, spec/utils/constants js가 test parse application에 구성되어 있는지 확인하는 것이 좋습니다 production parse application이 아닙니다 이 작업은 데이터를 삭제하므로, 위에서 생성한 빈 데이터베이스인지 확인하세요 이 함수는 우리가 구성한 parse sdk를 받아들이고, 또 다른 함수를 반환합니다 반환된 함수는 테이블 이름을 받아들이고, 해당 parse 테이블의 모든 데이터를 제거합니다 다시 말하지만, 함수를 반환하는 개념은 이상하게 보일 수 있지만, 이는 테스트 스펙이 parse 엔드포인트를 구성하고, 그 후에 해당 parse 엔드포인트의 테이블을 지울 함수를 참조할 수 있게 해줍니다 멋져요! 이제 테스트를 작성해봅시다! 6\ 적절한 매개변수가 전달되지 않으면 cloud function이 오류를 보낼 것임을 테스트합니다 cloud function은 특정 매개변수가 포함되어야 하며 실패해야 합니다 , 예를 들어, ‘firstname’이 전송되지 않은 경우 확실히 확인해봅시다 우리는 드디어 테스트 파일(spec/signup user spec js)을 편집할 것입니다 테스트 정의 전에 필요한 작업은 다음과 같습니다 parse nodejs sdk 가져오기 상수 가져오기 및 parse sdk를 테스트 서버를 가리키도록 구성하기 클라우드 함수 가져오기 “purge table” 유틸리티 가져오기 우리가 만든 응답 모의 객체 가져오기 다음 작업을 수행하면 됩니다 1 // hook into your testing server 2 var parse = require('parse/node'); 3 var constants = require(" /constants"); 4 // head over to your parse dash board for your test server, and grab your keys swap out the strings with the place holders below 5 parse initialize(constants application key, null, constants master key); 6 // if you are running a localhost parse server, set the serverurl accordingly 7 parse serverurl = 'https //parseapi back4app com' 8 var signupuser = require(" /cloud/cloud functions") signupuser(parse); 9 var purgetable = require(" /utils/purge parse table")(parse); 10 var responsestub = require(" /utils/response stub"); 이제 테스트 케이스를 추가해 보겠습니다 jasmine 소개 https //jasmine github io/2 1/introduction 는 구조를 더 잘 이해하는 데 도움이 될 수 있지만, 다음과 같이 보입니다(소개에서 발췌) 따라서 describe 블록은 테스트 스위트를 캡슐화하고, ‘it’ 블록은 케이스와 기대를 나타냅니다 ‘it’ 블록에 매개변수를 전달하면 비동기적으로 테스트를 실행할 수 있습니다 매개변수가 다음과 같이 호출될 때까지 테스트는 완료되지 않습니다 이것은 우리의 테스트 중 하나가 http를 사용할 것이므로, 이와 같은 방식으로 비동기적으로 실행되어야 한다는 점에서 유용합니다 http 사용은 nodejs에서 비차단 프로세스이기 때문입니다 추가적으로, jasmine은 테스트 생명 주기의 다양한 시점에서 실행될 수 있는 특별한 블록을 허용합니다 각 테스트 전에 모든 테이블을 삭제하고 싶으므로, beforeeach 블록에서 정리 코드를 실행할 것입니다 충분히 이야기했으니, 코드를 추가해봅시다! 아래 코드를 spec/signup user spec js의 이미 추가한 import 아래에 넣으세요 1 //spec/signup user spec js 2 // imports above 3 describe("signupuser", ()=> { 4 beforeeach((done) => { 5 /// purge the user and profile tables, and then proceed 6 promise all(\[purgetable("user"), purgetable("profile")]) 7 catch((e) => fail(e)) 8 then(() => done()); 9 }); 10 it ("should reject a request to signup that does not contain all the parameters", (done) => { 11 var responsestub = new responsestub(); 12 responsestub oncomplete() 13 then(() => fail("should have failed due to invalid parameters")) 14 catch((e) => {}) 15 then(() => done()); 16 17 signupuser({ params {}}, responsestub getstub()); 18 19 }); 20 }); 멋져요, 우리의 첫 번째 테스트가 완료되었습니다 beforeeach 블록에서 우리는 사용자 및 프로필 테이블을 정리합니다 그런 다음 첫 번째 테스트 케이스가 트리거됩니다 이는 signupuser 함수에 잘못된 매개변수를 전달하면 함수가 오류를 전송하는지 확인합니다 이 함수는 응답 스텁을 사용하여 함수가 궁극적으로 거부되었는지 확인합니다 ‘signupuser’가 실패할 것이기 때문에, 스텁의 초기 ‘then’ 블록은 호출되지 않아야 합니다 호출된다면, 우리의 테스트는 실패합니다! 다음 명령어를 사용하여 테스트를 실행하세요 다음과 같은 출력이 표시되어야 합니다 7\ 데이터 지속성에 대한 테스트 여러분이 한 번 더 테스트를 할 수 있기를 바랍니다! 우리는 우리의 클라우드 함수가 제대로 실행될 때, 데이터베이스가 예상대로 될 것인지 확인할 것입니다 프로필이 존재하고, 사용자 객체에 대한 참조가 있으며, 두 객체 모두 예상되는 속성을 가지고 있습니다 다음 블록을 기존의 ‘describe’ 스위트 블록에 추가하세요 1 //spec/signup user spec js 2 // inside describe 3 it ("should signup a user, and also create a profile that contains a reference to the user", (done) => { 4 var responsestub = new responsestub(); 5 var stub = responsestub getstub(); 6 signupuser({ 7 params { 8 firstname "john", 9 lastname "smith", 10 email "jsmith\@example com", 11 username "jsmith1", 12 password "secretcatchphrase1" 13 }, 14 }, 15 stub 16 ); 17 responsestub oncomplete() 18 then((resp) => { 19 var profileq = new parse query("profile"); 20 profileq equalto("lastname", "smith"); 21 return profileq find({usemasterkey true}); 22 }) 23 // check to make sure the profile we retrieve is valid 24 then((profiles) => { 25 if (profiles length === 0) throw new error("no profile's found"); 26 expect(profiles\[0] get('firstname')) tobe("john"); 27 // get the corresponding user 28 return profiles\[0] get("user") fetch({usemasterkey true}) 29 }) 30 // check to make sure the user is what we expect 31 then((user) => { 32 expect(user getusername()) tobe("jsmith1"); 33 }) 34 catch((e) => { 35 console log(e) 36 fail(e); 37 }) 38 then(() => done()); 39 }); 좋습니다, 이건 많으니 어떤 일이 발생하는지 살펴보겠습니다 우리는 첫 번째 테스트 케이스와 같이 응답 모의 객체를 인스턴스화합니다 그런 다음 유효한 valid 매개변수를 포함하는 요청 더블과 응답 모의 객체로 signupuser를 실행합니다 (6 16행) 다음으로, 이 코드는 모의 객체의 oncomplete 메서드를 듣고 있으며, 이는 promise를 반환합니다 응답 error가 호출되면 promise는 거부되고, 응답 success가 호출되면 해결됩니다 모든 거부는 promise 체인이 catch 블록으로 건너뛰게 합니다 따라서 테스트가 promise가 거부되면 실패해야 하므로 fail 메서드는 catch 블록에 배치됩니다 promise의 응답은 프로필 객체로 해결되어야 합니다 해결되면, 우리는 생성한 것과 동일한 성을 가진 프로필을 쿼리할 것입니다 (19 21행) 그런 다음 테스트는 프로필의 ‘firstname’이 우리가 전달한 것과 동일한지 확인합니다 (25 26행) 다음 블록은 프로필과 연결된 사용자 객체를 가져옵니다 parse 객체 포인터는 별도로 가져오므로, 또 다른 promise 블록이 필요합니다 마지막으로, 코드는 해당 사용자가 signupuser 함수에 전달된 사용자 이름을 가지고 있는지 확인합니다 그런 다음 테스트가 종료됩니다 계속해서 스위트를 한 번 더 실행하세요 계속해서 다음을 사용하여 테스트를 실행하세요 다음 출력을 볼 수 있어야 합니다 멋져요! 우리는 클라우드 코드를 작성하고 테스트 프레임워크를 통합했습니다 결론 만약 당신이 길을 잃었거나, 이 예제의 코드를 원한다면 github 저장소 https //github com/back4app/template cloud code unit test 로 가세요 지침을 따라 다운로드하고 실행하세요 무언가가 명확하지 않거나 작동하지 않는 경우, 제 gmail(jackconsidine3)로 연락해 주세요 이 튜토리얼이 즐거웠고, 통찰력을 얻으셨기를 바랍니다!