![](/img/trans.png)
[英]TypeError: Cannot read properties of undefined (reading 'listen') when testing with Jest, Supertest, Express, Typescript
[英]Express/Typescript testing with Jest/Supertest
我目前正在嘗試測試快速 API,我正在使用 Jest 和 Supertest,但我似乎無法讓它工作。
我的代碼是:
router.get('/', async (req: Request, res: Response) => {
const products: ProductType[] = await ProductModel.find({});
res.send(products);
});
我的測試是:
describe('GET /', () => {
it('calls ProductModel.find and returns products', async () => {
const mockproducts = 'this is a product';
ProductModel.find = jest.fn().mockResolvedValueOnce(mockproducts);
const response = await request(products).get('/');
expect(response).toBe(mockproducts);
});
});
所以基本上,模擬的解析值都可以正常工作,但是當我運行測試時, res.send 不起作用。
TypeError: res.send is not a function
誰能告訴這里的問題是什么?
謝謝!
誰能告訴這里的問題是什么?
當可以避免時,您在單元測試中使用supertest
。 supertest
也接受您的 express 應用程序的實例,並且似乎提供了products
? 或者products
是您的快遞實例? 您可能會發現的另一個問題是ProductModel.find
直到調用測試后才被模擬,因為您正在使用全局實例。
在測試時,我們可以通過設計具有清晰抽象和測試的代碼來使我們的生活更輕松。
設計代碼時,設計代碼以接受依賴項實例作為參數/屬性:
// as an argument
function makeHttpRequest(path, httpClient: AxoisInstance) {
return httpClient.get(path);
}
// as a property of object/class
class DependsOn {
constructor(private readonly httpClient: AxoisInstance) {}
request(path: string) {
return this.httpClient.get(path);
}
}
這使我們的測試更容易,因為我們可以自信地說正確的實例(真實或模擬)已提供給 controller、服務、存儲庫等。
這也避免了使用以下內容:
// ... some bootstrap function
if (process.env.NODE_ENV === 'test') {
someInstance = getMockInstance()
} else {
someInstance = RealInstance();
}
當您處理請求時,需要發生一些事情:
ProductModel
或數據層)您目前擁有所有這些內聯(我認為我們中的 99.99% 的人在選擇 Express 時都會這樣做)。
// product.routes.ts
router.get('/', ProductController.get); // pass initialised controller method
// product.controller.ts
class ProductController {
constructor(private readonly service: ProductService) {}
get(request: Request, response: Response) {
// do anything with request, response (if needed)
// if you need validation, try middleware
response.send(await this.service.getAllProducts());
}
}
// product.service.ts
class ProductService {
// Model IProduct (gets stripped on SO)
constructor(private readonly model: Model) {}
getAllProducts() {
return this.model.find({});
}
}
我們現在剩下幾個可以輕松測試的組件,以確保正確的輸入產生正確的 output。 在我看來,jest 是模擬方法、類和其他一切的最簡單工具之一,只要你有良好的抽象允許你這樣做。
// product.controller.test.ts
it('should call service.getAllProducts and return response', async () => {
const products = [];
const response = {
send: jest.fn().mockResolvedValue(products),
};
const mockModel = {
find: jest.fn().mockResolvedValue(products),
};
const service = new ProductService(mockModel);
const controller = new ProductController(service);
const undef = await controller.get({}, response);
expect(undef).toBeUndefined();
expect(response.send).toHaveBeenCalled();
expect(response.send).toHaveBeenCalledWith(products);
expect(mockModel.find).toHaveBeenCalled();
expect(mockModel.find).toHaveBeenCalledWith();
});
// product.service.test.ts
it('should call model.find and return response', async () => {
const products = [];
const mockModel = {
find: jest.fn().mockResolvedValue(products),
};
const service = new ProductService(mockModel);
const response = await service.getAllProducts();
expect(response).toStrictEqual(products);
expect(mockModel.find).toHaveBeenCalled();
expect(mockModel.find).toHaveBeenCalledWith();
});
// integration/e2e test (app.e2e-test.ts) - doesn't run with unit tests
// test everything together (mocking should be avoided here)
it('should return the correct response', () => {
return request(app).get('/').expect(200).expect(({body}) => {
expect(body).toStrictEqual('your list of products')
});
})
對於您的應用程序,您需要確定將依賴項注入正確類的合適方法。 您可以決定接受所需模型的main
function 適合您,或者可以決定像https://www.npmjs.com/package/injection-js這樣更強大的東西。
如果您希望避免使用對象,請接受實例作為 function 參數: productServiceGetAll(params: SomeParams, model?: ProductModel)
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.