模拟类
模拟类
ES6中所提供的class本质上是一个语法糖,背后实际上是一个构造函数,因此在对类进行测试的时候,可以使用jest.mock或者jest.spyOn来进行模拟测试。
如下是两个类,后续的所有测试用例将围绕此展开:
- productReview.ts
- reviewCollector.ts
export default class ProductReview {
private _name: string
private _review: string
constructor(name: string, review: string) {
this._name = name
this._review = review
}
get name(): string {
return this._name
}
get review(): string {
return this._review
}
}
import ProductReview from './productReview'
export default class ReviewCollector {
private _reviewList: ProductReview[]
private _productList: string[]
constructor() {
this._reviewList = []
this._productList = []
}
public addReview(productReview: ProductReview): void {
this.reviewList.push(productReview)
let found: boolean = false
for (let i = 0; i < this.productList.length; i++) {
if (
this.productList[i] === productReview.name
) {
found = true
break
}
}
if (!found) {
this.productList.push(productReview.name)
}
}
public getNumGoodReview(productName: string): number {
let numGoodReviews = 0
for (let i = 0; i < this.reviewList.length; i++) {
if (this.reviewList[i].name === productName) {
let review = this.reviewList[i].review
if (review.includes('Good')) {
numGoodReviews++
}
}
}
return numGoodReviews
}
public logReview() {
for (let i = 0; i < this.productList.length; i++) {
console.log(this.productList[i])
}
}
get productList() {
return this._productList
}
get reviewList() {
return this._reviewList
}
}
模拟构造器
在测试一个模块的时候,如果这个模块依赖了其它模块,为了屏蔽其影响,需要模拟一个完整的依赖,这种情况下可通过jest.mock方法来完成。
在上述示例中ReviewCollector依赖ProductReview,因此可以模拟ProductReview:
import ReviewCollector from '../src/class/reviewCollector'
import ProductReview from '../src/class/productReview'
jest.mock('../src/class/productReview', () => {
return jest
.fn()
.mockImplementation(
(name: string, review: string) => {
return {
name,
review
}
}
)
})
基本测试
describe('Test ReviewCollector', () => {
let collector: ReviewCollector
beforeEach(() => {
collector = new ReviewCollector()
})
test('Add a review', () => {
const review = new ProductReview(
'Product A',
'Good'
)
collector.addReview(review)
expect(collector.getNumGoodReview('Product A')).toBe(1)
expect(collector.productList).toContain('Product A')
})
test('Get good review', () => {
const review1 = new ProductReview('Product A','Bad')
const review2 = new ProductReview('Product A','Good')
const review3 = new ProductReview('Product B','Good')
collector.addReview(review1)
collector.addReview(review2)
collector.addReview(review3)
expect(collector.getNumGoodReview('Product A')).toBe(1)
expect(collector.getNumGoodReview('Product B')).toBe(1)
})
})
模拟方法
通过jest.spyOn监听某个方法的调用:
const ReviewCollectorMock = jest
.spyOn(ReviewCollector.prototype, 'logReview')
.mockImplementation(() => 'Loged Review')
test('Test methods', () => {
const collector = new ReviewCollector()
const review = new ProductReview('Product A', 'Good')
collector.addReview(review)
collector.logReview()
expect(ReviewCollectorMock).toHaveBeenCalledTimes(1)
})
模拟静态方法
静态方法与实例方法类似:
const ReviewCollectorStaticMock = jest
.spyOn(ReviewCollector, 'showInfo')
.mockImplementation(() => 'Static method')
test('Test static methods', () => {
const result = ReviewCollector.showInfo()
expect(ReviewCollectorStaticMock).toHaveBeenCalled()
expect(result).toBe('Static method')
})
getter/setter
const ReviewCollectorSetterGetterMock = jest.spyOn(
ReviewCollector.prototype,
'productList',
'get'
)
test('Test getter', () => {
const collector = new ReviewCollector()
const review = new ProductReview('Product A', 'Good')
collector.addReview(review)
expect(ReviewCollectorSetterGetterMock).toHaveBeenCalled()
expect(collector.productList).toEqual(['Product A'])
})
模拟非默认导出
如果类不是默认导出,那么需要返回一个具有与类导出名称相同的键的对象:
jest.mock('../src/class/productReview', () => {
return {
ProductReview: jest
.fn()
.mockImplementation(
(name: string, review: string) => {
return {
name,
review
}
}
)
}
})