node.js에서 데이터베이스를 조롱합니까?


79

이 경우 mongodb블로그 REST API의 백엔드로 사용하는 node.js 애플리케이션의 데이터베이스를 어떻게 모의 처리 합니까?

물론 데이터베이스를 특정 데이터베이스로 설정할 수는 testing있지만 여전히 데이터를 저장하고 코드 만 테스트하지 않고 데이터베이스도 테스트하므로 실제로 단위 테스트가 아니라 통합 테스트를 수행하고 있습니다.
그래서 어떻게해야합니까? 응용 프로그램과 db 사이의 중간 계층으로 데이터베이스 래퍼를 만들고 테스트 할 때 DAL을 교체 하시겠습니까?

// app.js  
var express = require('express');
    app = express(),
    mongo = require('mongoskin'),
    db = mongo.db('localhost:27017/test?auto_reconnect');

app.get('/posts/:slug', function(req, res){
    db.collection('posts').findOne({slug: req.params.slug}, function (err, post) {
        res.send(JSON.stringify(post), 200);
    });
});

app.listen(3000);

// test.js
r = require('requestah')(3000);
describe("Does some testing", function() {

  it("Fetches a blogpost by slug", function(done) {
    r.get("/posts/aslug", function(res) {
      expect(res.statusCode).to.equal(200);
      expect(JSON.parse(res.body)["title"]).to.not.equal(null);
      return done();
    });

  });
));

답변:


128

데이터베이스 소프트웨어로 테스트하지 않고는 데이터베이스 관련 코드를 제대로 테스트 할 수 없다고 생각합니다. 테스트중인 코드가 자바 스크립트뿐만 아니라 데이터베이스 쿼리 문자열이기 때문입니다. 귀하의 경우 쿼리가 단순 해 보이지만 영원히 그렇게 믿을 수는 없습니다.

따라서 모든 데이터베이스 에뮬레이션 계층은 반드시 전체 데이터베이스를 구현합니다 (아마도 디스크 스토리지 제외). 그러면 단위 테스트라고 부르더라도 데이터베이스 에뮬레이터와 통합 테스트를 수행하게됩니다. 또 다른 단점은 데이터베이스 에뮬레이터가 데이터베이스와 비교하여 다른 버그 세트를 가질 수 있으며 결국 데이터베이스 에뮬레이터와 데이터베이스 모두에 대해 코드를 작성해야 할 수 있다는 것입니다 (IE, Firefox, Chrome 등의 상황과 유사합니다. ).

따라서 제 생각에는 코드를 올바르게 테스트하는 유일한 방법은 실제 데이터베이스와 인터페이스하는 것입니다.


1
당신은 좋은 지적을합니다. 단위 테스트가 경이적인 목적 (예 : 격리)을 제공하는 동안 통합 테스트에 대한 강점을 만들었습니다.
Mike Perrenoud 2015 년

4
@MichaelPerrenoud : 나는 christkv의 대답에 명시된 규칙을 좋아합니다 : "당신이 소유하지 않은 것을 조롱하지 마십시오" . 왜 그것이 나쁜 생각인지 자세히 설명하지는 않지만 기억하기 쉬운 규칙입니다.
slebetman 2015 년

1
나는이 답변에 동의하지 않습니다. meteorjs에서는 테스트를 실행할 때 어떻게 든 테스트 DB를 설정하고 (모의 라이브러리가 아니라 임시 파일이라고 가정합니다) 매우 편리합니다. mongodb와 똑같이 작동하고 자체적으로 청소하는 객체를 갖는 것이 매우 유용합니다. 모두 메모리에 있든 임시 파일에 있든 구현 세부 사항이므로 코드를 복제 할 필요가 없습니다. 나는 운전자를 만드는 사람이 모의 객체를 만드는 사람이어야한다는 데 동의합니다.
Uri

나는 또한이 대답에 동의하지 않는다고 생각합니다. OP의 질문은 컨트롤러와 데이터베이스뿐이라는 점에서 단순했습니다. DB에서 인터넷으로 파이프하는 것이 아니라 서버 서버를 만드는 모든 애플리케이션 로직은 어떻습니까? 유효성을 검사하고 데이터베이스에 넣을 개체가 있다고 상상하면 상호 작용이 여전히 작동하는지 확인하는 통합 테스트와 모든 유효성 검사를 확인하는 단위 테스트와 같은 것을 상상하는 것이 공평하지 않습니까? 이 대답을 문자 그대로 취하면 데이터베이스에서 시작된 데이터로 어떻게 테스트 할 수 있습니까? 빌드는 얼마나 걸리나요 ??
user2152081

1
봐요, DB 호출을 조롱하는 것은 정말 어리 석고 바쁜 일로 이어집니다. 나는 사람들이 전체 테스트 포인트를 놓치고 있다고 생각합니다. 입력이 출력과 일치 함을 보여주는 것입니다. DB를 호출하는 함수의 경우 해당 테스트에 db 호출이 포함되지 않는 한 확실히 알 수 없습니다. 이를 수행하는 가장 좋은 방법은 테스트 구성이 메모리에서 실행중인 MongoDB의 인스턴스를 가리 키도록하는 것입니다. 이렇게하면 디스크 I / O를 처리 할 필요가 없으며 메모리에서 실행되는 '조롱'의 주요 요점도 충족 할 수 있습니다.
Glstunna

43

조롱에 관한 일반적인 경험 법칙이 있습니다.

소유하지 않은 것을 조롱하지 마십시오.

데이터베이스를 모의하려면 추상화 된 서비스 계층 뒤에 숨기고 해당 계층을 모의합니다. 그런 다음 실제 서비스 계층을 통합 테스트해야합니다.

개인적으로 나는 테스트를 위해 모의를 사용하지 않고이를 위에서 아래로 디자인하는 데 사용하여 이동하면서 서비스 계층을 조롱하고 결국에는 이러한 계층을 구현하고 통합 테스트를 작성하는 데 도움이됩니다. 테스트 도구로 사용하면 테스트를 매우 취약하게 만드는 경향이 있으며 최악의 경우 실제 동작과 조롱 된 동작간에 차이가 발생합니다.


물론 리포지토리 또는 게이트웨이 뒤에 숨겨서 모의를 사용하여 테스트 주도 접근 방식을 유도하고 단위 테스트를 격리 할 수 ​​있습니다. 그렇다면 테스트에 모의를 사용하지 않는다는 의미는 무엇입니까? 모의 게이트웨이 / 저장소를 테스트에 그대로 유지 한 다음 어떻게 든 인터페이스를 사용하여 인터페이스를 통해 저장소의 실제 구현을 지정합니다.
PositiveGuy

타사 API를 어떻게 처리합니까? VCR과 같은 도우미?
Dogweather

당신은 최고의 선생님입니다!
마르코 Lazzeri

41

지금까지 선택한 답변이나 다른 답변에 동의하지 않습니다.

QA에 들어가기 전에 혼란스럽고 DB 스키마와 코드에 대한 복잡한 변경으로 인해 발생한 오류를 포착 할 수 있다면 멋지지 않을까요? 나는 대다수가 예라고 외칠 것이라고 장담한다!

가장 확실하게 DB 스키마를 격리하고 테스트해야합니다. 그리고 에뮬레이터 나 무거운 이미지를 기반으로하거나 DB와 머신의 재현을 기반으로하지 않습니다. 이것이 바로 SQLite와 같은 것입니다. 실행중인 메모리 경량 인스턴스와 메모리 인스턴스에서 변경되지 않는 정적 데이터를 기반으로 모의 작업을 수행합니다. 즉, 실제로 DB를 격리하여 테스트하고 테스트를 신뢰할 수 있음을 의미합니다. 그리고 분명히 그것은 메모리, 뼈대에 있기 때문에 빠르며 테스트 실행이 끝날 때 폐기됩니다.

그렇기 때문에 사용중인 DB 엔진 / 런타임의 매우 가벼운 메모리 인스턴스로 내 보내진 SCHEMA를 테스트해야하며, 매우 적은 양의 정적 데이터를 추가하면 격리 된 모의 DB가됩니다.

정기적으로 (자동화 된 방식으로) 실제 DB에서 실제 스키마를 내보내고 QA에 푸시 할 때마다 라이트 인 메모리 DB 인스턴스로 가져 오기 / 업데이트하면 DB 관리자 또는 다른 사용자가 최신 DB 변경 사항을 즉시 알 수 있습니다. 최근에 스키마를 변경 한 개발자는 테스트를 위반했습니다.

최선을 다해 답변 해주신 것에 박수를 보내는 동안 할 수 있다면 현재 답변에 반대표를 던지 겠지만 저는 새롭고 아직 그렇게 할 수있을만큼 충분한 평판을 얻지 못했습니다.

"당신이 소유하지 않은 것을 조롱하지 마십시오"라고 답한 사람에 관해서. 나는 그가 "당신이 소유하지 않은 것을 시험하지 마십시오"라고 말하고자했던 것 같습니다. 그러나 당신은 당신이 소유하지 않은 것을 조롱합니다! 왜냐하면 그것들은 격리 될 필요가있는 테스트 대상이 아니기 때문입니다!

저는 여러분과 HOW를 공유 할 계획이며 실제 예제 JS 코드를 사용하여 향후 시점에이 게시물을 업데이트 할 것입니다!

이것은 많은 테스트 주도 팀이 항상하는 일입니다. 방법을 이해하면됩니다.


5
나는 찬성하고 싶지만 질문을 완화하고 해결책을 제공하지 않으면 할 수 없습니다. 기회가 생기면 게시물을 업데이트하십시오.
Shanimal

5
2018 년에도 여전히 "어떻게"가 없는데, 확실히 더 많은 것을 읽고 싶었습니다.
MacK

3
나는 3 년 이후로 투표를했지만 아직 방법이 없습니다.
ian

5

어떤 언어로든 단위 테스트 DB 코드에 대해 선호하는 접근 방식은 저장소 추상화를 통해 Mongo에 액세스하는 것입니다 ( http://iainjmitchell.com/blog/?p=884 여기에 예제가 있습니다 ). 구현은 노출 된 DB 특정 기능 측면에서 다양하지만 자체 로직에서 모든 Mongo 코드를 제거하면 단위 테스트를 수행 할 수 있습니다. Mongo Repository 구현을 간단하게 스텁 아웃 된 버전으로 교체하기 만하면됩니다. 예를 들어, 단순한 메모리 내 사전 컬렉션에 객체를 저장하면됩니다.

DB 종속성없이 이러한 방식으로 자신의 코드를 단위 테스트하는 이점을 얻을 수 있지만 다른 사람들이 가지고있는 것처럼 실제 데이터베이스의 특이성을 모방 할 수 없기 때문에 여전히 기본 DB에 대해 통합 테스트를 수행해야합니다. 여기에 말했다. 내가 찾은 종류는 안전 모드에서 색인을 생성하는 것과 안전 모드를 사용하지 않는 것만 큼 간단합니다. 특히, 고유 인덱스가있는 경우 더미 메모리 구현은 모든 경우에이를 존중할 수 있지만 Mongo는 안전 모드 없이는 그렇지 않습니다.

따라서 일부 작업에 대해서는 여전히 DB에 대해 테스트해야하지만 스텁 아웃 리포지토리 구현으로 자신의 논리를 적절하게 단위 테스트 할 수 있습니다.


그러나 어느 시점에서 실제 구현 코드는 실제 데이터 호출을 참조해야합니다. 실제 데이터 레이어 쿼리 코드에 인터페이스를 저장소에 주입한다고 가정합니까?
PositiveGuy

1
Docker를 사용해보십시오. Docker를 사용하여 시나리오에 대한 특정 테스트 데이터로 초기화 된 데이터베이스를 실행하는 컨테이너를 실행하여 데이터베이스 및 패키지 설치와 관련된 수년간 악몽 같은 구성 문제를 해결했습니다. 사실 저는 3 개의 컨테이너 스택을 실행합니다. 하나는 DB, 하나는 애플리케이션 코드, 다른 하나는 테스트 드라이버입니다. 데이터 세트의 크기가 중간이면 이러한 스택의 병렬 인스턴스를 스핀 업하여 테스트주기를 상당히 단축 할 수도 있습니다.
ovo

4

조롱의 목적은 복잡성과 단위 테스트 자체 코드를 건너 뛰는 것입니다. e2e 테스트를 작성하려면 db를 사용하십시오.

단위 테스트를 위해 테스트 DB를 설정 / 해체하는 코드를 작성하는 것은 기술적 인 부채이며 믿을 수 없을 정도로 불만족 스럽습니다.

npm에는 모의 라이브러리가 있습니다.

몽고 - https://www.npmjs.com/package/mongomock

몽구스-https: //www.npmjs.com/package/mockgoose

필요한 기능을 지원하지 않는 경우 실제 기능을 사용해야 할 수 있습니다.


1
몽고 - 모의 내가 그것을 사용하기 시작 문제점을하고 마지막에 내가 testOnly 데이터베이스와 실제 소프트웨어를 사용하여 종료 할 수 있습니다 예를 들어, 집계 작업을 지원하지 않습니다
zardilior

이 목적을 패배 있도록 또한 많은 재료가 고장 MongoDB를 위해 이리저리은 몽고 - 모의 변경시
zardilior을

3

저는이 딜레마가 있었고 테스트 DB로 작업하고 테스트가 시작될 때마다 청소하기로 결정했습니다. (모든 것을 삭제하는 방법 : https://stackoverflow.com/a/25639377/378594 )

NPM을 사용하면 db 파일을 생성하고 나중에 정리하는 테스트 스크립트를 만들 수도 있습니다.


이것은 실제로 좋은 접근 방식이며 심각한 CI / CD 파이프 라이닝을 수행하는 모든 사람에게 그렇게 할 것을 권장합니다. 오늘날의 JavaScript 도구를 사용하면 테스트 실행 전후에 쉽게 테스트 데이터베이스를 생성 / 삭제할 수 있습니다. 이 접근 방식이 개발 중에 적합한 지 논쟁하고 있지만 (모든 코드 변경시 데이터베이스를 삭제하고 생성하고 싶지는 않음) 이에 대한 다른 솔루션이 있습니다. 최소한 데이터를 모의하고 테스트 환경에 연결하는 별도의 플러그인 통합을 유지해야하는 문제를 해결합니다.
Nicky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.