多次开玩笑 doMock 同一个方法
Jest doMock the same method multiple times
我想测试以下部分代码:
// ... code above
const created = async payload => {
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
if (!model.exists) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Grab the categories field
const categories = model.get('categories') // <--- 2nd .get() occurence
// Product is either empty or does not exists at all
if (!categories || categories.length < 1) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Otherwise remove from the orphans collection
await deleted(payload.sku)
}
}
}
我不知道如何在同一个回调中正确模拟文件两次。这是我得到的:
test.only('it should react when an event "created" has been fired', async () => {
const spy = jest.fn()
jest.doMock('@google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: () => {
spy()
}
}
},
set: () => {
spy()
}
}
}
}
}
})
const observer = require('./product')
await observer('created', {})
await expect(spy.mock.calls.length).toBe(1)
})
我收到这个错误:
● it should react when an event "created" has been fired
TypeError: model.get is not a function
25 | } else {
26 | // Grab the categories field
> 27 | const categories = model.get('categories')
| ^
28 |
29 | // Product is either empty or does not exists at all
30 | if (!categories || categories.length < 1) {
at created (app/observers/product.js:27:30)
at Object.<anonymous>.module.exports (app/observers/product.js:6:28)
at Object.<anonymous> (app/observers/product.spec.js:34:3)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 skipped, 2 total
Snapshots: 0 total
Time: 0.147 s, estimated 1 s
Ran all test suites matching /app\/observers\/product.spec.js/i.
测试同一模拟 get()
方法的两个场景的工作解决方案是什么?
在您的代码中:
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
如果我们查看您的模拟,doc
returns 的 get
方法:
{
exists: () => {
spy()
}
}
没有名为 get
的 属性,因此它是 undefined
(而不是函数)。
我猜你只需要将这部分更改为:
{
exists: true, // can be false
get: spy,
}
你的问题应该已经解决了。
顺便说一句,您还可以将 set
方法的 mock 更改为 set: spy
。或者你可以将它保持为 set: () => { spy() }
,但如果你想模拟它,你至少应该 return 这个值:set: () => { spy() }
.
现在,关于如何正确模拟多次,这是您可以做的:
const observer = require('./product')
const spyGet = jest.fn()
const spySet = jest.fn() // I like having different mocks, if one function use get & set, tests will be clever & more readable if you use different spies
describe('on event "created" fired', () => {
const categories = []
beforeEach(() => {
// I put mocks here to make test more readable
jest.doMock('@google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: true,
get: spyGet,
}
},
set: spySet
}
}
}
}
})
spyGet.mockResolvedValueOnce(categories) // you can also use mockResolvedValue, but mockResolvedValueOnce allow you to mock with different values on the same test & same mock
})
it.only('should get categories', async () => {
await observer('created', {})
// here's all the ways you can test it
expect(spyGet).toBeCalledTimes(1)
expect(spyGet.mock.calls.length).toBe(1)
expect(spyGet).toBeCalledWith('categories')
expect(spyGet).toHaveBeenNthCalledWith(1, 'categories')
})
})
注意:如果你没有将它设置到 jest 配置中,你应该在测试之间手动重置和清除你的模拟(在 afterEach 或 beforeEach 中)。
我想测试以下部分代码:
// ... code above
const created = async payload => {
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
if (!model.exists) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Grab the categories field
const categories = model.get('categories') // <--- 2nd .get() occurence
// Product is either empty or does not exists at all
if (!categories || categories.length < 1) {
// Add product to the orphans collection
await db.collection('orphans').doc(payload.sku).set(payload)
} else {
// Otherwise remove from the orphans collection
await deleted(payload.sku)
}
}
}
我不知道如何在同一个回调中正确模拟文件两次。这是我得到的:
test.only('it should react when an event "created" has been fired', async () => {
const spy = jest.fn()
jest.doMock('@google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: () => {
spy()
}
}
},
set: () => {
spy()
}
}
}
}
}
})
const observer = require('./product')
await observer('created', {})
await expect(spy.mock.calls.length).toBe(1)
})
我收到这个错误:
● it should react when an event "created" has been fired
TypeError: model.get is not a function
25 | } else {
26 | // Grab the categories field
> 27 | const categories = model.get('categories')
| ^
28 |
29 | // Product is either empty or does not exists at all
30 | if (!categories || categories.length < 1) {
at created (app/observers/product.js:27:30)
at Object.<anonymous>.module.exports (app/observers/product.js:6:28)
at Object.<anonymous> (app/observers/product.spec.js:34:3)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 skipped, 2 total
Snapshots: 0 total
Time: 0.147 s, estimated 1 s
Ran all test suites matching /app\/observers\/product.spec.js/i.
测试同一模拟 get()
方法的两个场景的工作解决方案是什么?
在您的代码中:
const model = await db.collection('models').doc(payload.model)
.get() // <--- 1st .get() occurence
如果我们查看您的模拟,doc
returns 的 get
方法:
{
exists: () => {
spy()
}
}
没有名为 get
的 属性,因此它是 undefined
(而不是函数)。
我猜你只需要将这部分更改为:
{
exists: true, // can be false
get: spy,
}
你的问题应该已经解决了。
顺便说一句,您还可以将 set
方法的 mock 更改为 set: spy
。或者你可以将它保持为 set: () => { spy() }
,但如果你想模拟它,你至少应该 return 这个值:set: () => { spy() }
.
现在,关于如何正确模拟多次,这是您可以做的:
const observer = require('./product')
const spyGet = jest.fn()
const spySet = jest.fn() // I like having different mocks, if one function use get & set, tests will be clever & more readable if you use different spies
describe('on event "created" fired', () => {
const categories = []
beforeEach(() => {
// I put mocks here to make test more readable
jest.doMock('@google-cloud/firestore', () => class {
collection () {
return {
doc: () => {
return {
get: () => {
return {
exists: true,
get: spyGet,
}
},
set: spySet
}
}
}
}
})
spyGet.mockResolvedValueOnce(categories) // you can also use mockResolvedValue, but mockResolvedValueOnce allow you to mock with different values on the same test & same mock
})
it.only('should get categories', async () => {
await observer('created', {})
// here's all the ways you can test it
expect(spyGet).toBeCalledTimes(1)
expect(spyGet.mock.calls.length).toBe(1)
expect(spyGet).toBeCalledWith('categories')
expect(spyGet).toHaveBeenNthCalledWith(1, 'categories')
})
})
注意:如果你没有将它设置到 jest 配置中,你应该在测试之间手动重置和清除你的模拟(在 afterEach 或 beforeEach 中)。