2017-08-20 124 views
2

我試圖測試一個REST API,使用express和mongoose構建,我使用的是HTTP調用的笑話和超級特技;我也相對較新的測試與JavaScript。Jest測試貓鼬模型實例

當測試一個創建url時,我不想確保實例化只是使用req.body對象來調用,但我不知道該怎麼做,在閱讀了很多關於模擬對象和存根之間差異的內容之後,一些玩笑文檔我的最後一次嘗試是這樣的:

test('Should instantiate the model using req.body', done => { 

    const postMock = jest.fn(); 

    const testPost = { 
    name: 'Test post', 
    content: 'Hello' 
    }; 

    postMock.bind(Post); // <- Post is my model 

    // I mock the save function so it doesn't use the db at all 
    Post.prototype.save = jest.fn(cb => cb(null, testPost)); 

    // Supertest call 
    request(app).post('/posts/') 
    .send(testPost) 
    .then(() => { 
    expect(postMock.mock.calls[0][0]).toEqual(testPost); 
    done(); 
    }) 
    .catch(err => {throw err}); 

}); 

此外,我想知道如何手動未能在承諾拒絕測試,因此它不會拋出Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.

回答

4

因爲它看起來,你正在執行更多的集成測試,而不是隔離路由處理函數本身並僅測試th在。

首先,我會掙脫了/posts/到自己的文件處理程序(假設你沒有這樣做了):

controllers/post-controller.js

const Post = require('./path/to/models/post') 

exports.store = async (req, res) => { 
    const post = await new Post(req.body).save() 
    res.json({ data: post } 
} 

接下來只需使用處理器無論你定義你的路由:

const express = require('express') 
const app = express() 
const postController = require('./path/to/controllers/post-controller') 

app.post('/posts', postController.store) 

有了這個抽象,我們現在可以隔離我們postController.store並測試它的效果與req.body。現在,因爲我們需要模擬貓鼬避免碰到一個實際的數據庫,你可以創建一個嘲笑Post像這樣(用你已有的代碼):

path/to/models/__mocks__/post.js

const post = require('../post') 

const mockedPost = jest.fn() 
mockedPost.bind(Post) 

const testPost = { 
    name: 'Test post', 
    content: 'Hello' 
} 


Post.prototype.save = jest.fn(cb => { 
    if (typeof cb === 'function') { 
    if (process.env.FORCE_FAIL === 'true') { 
     process.nextTick(cb(new Error(), null)) 
    } else { 
     process.nextTick(cb(null, testPost)) 
    } 
    } else { 
    return new Promise((resolve, reject) => { 
     if (process.env.FORCE_FAIL === 'true') { 
     reject(new Error()) 
     } else { 
     resolve(testPost) 
     } 
    }) 
    } 
}) 

module.exports = mockedPost 

注意在檢查process.env.FORCE_FAIL如果無論什麼原因你想失敗它。

現在我們準備測試,使用req.body作品:

post-controller.test.js

// Loads anything contained in `models/__mocks__` folder 
jest.mock('../location/to/models') 

const postController = require('../location/to/controllers/post-controller') 

describe('controllers.Post',() => { 
    /** 
    * Mocked Express Request object. 
    */ 
    let req 

    /** 
    * Mocked Express Response object. 
    */ 
    let res 

    beforeEach(() => { 
    req = { 
     body: {} 
    } 
    res = { 
     data: null, 
     json(payload) { 
     this.data = JSON.stringify(payload) 
     } 
    } 
    }) 

    describe('.store()',() => { 
    test('should create a new post', async() => { 
     req.body = { ... } 
     await postController(req, res) 
     expect(res.data).toBeDefined() 

     ... 
    }) 

    test('fails creating a post',() => { 
     process.env.FORCE_FAIL = true 
     req.body = { ... } 

     try { 
     await postController.store(req, res) 
     } catch (error) { 
     expect(res.data).not.toBeDefined() 

     ... 
     } 
    }) 

    }) 
}) 

此代碼是未經測試,但我希望它有助於您的測試。