> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-zh/gong-xian-zhe-zhi-nan/testing-standards/testing-services-deprecated.md).

# 测试服务（已弃用）

{% hint style="warning" %}
这是一种用于测试服务的已弃用方法。对于新服务，请参阅 [测试服务（众所周知组件）](/contributor/contributor-zh/gong-xian-zhe-zhi-nan/testing-standards/testing-services-wkc.md).
{% endhint %}

服务应主要使用以下方式进行测试： **API 测试**，也就是一组通过 API 来执行服务代码的测试：先启动服务，并对其外部依赖（数据库和 API）进行模拟。 **单元测试** 应在遇到代码中的工具函数部分、需要覆盖大量情况或性能不佳、因而无法或难以使用 API 测试进行测试时加入。其背后的原因是，由于我们的微服务架构会减少职责，从而减少需要测试的代码量，服务逻辑较为简单，因此在确保服务正常工作时，API 测试是投入时间与价值比最高的选择。

## 测试栈

服务必须使用以下方式进行测试： [Jest](https://jestjs.io/) 作为主要测试框架，并使用 [supertest](https://github.com/visionmedia/supertest) 作为搭建服务器并对其进行测试的框架。

## 目录结构

由于服务可能同时拥有 API 测试和单元测试，因此测试文件将放在多个位置：

* 单元测试必须与其所测试的文件或模块放在一起，文件名相同，但扩展名为 `spec.ts` 而不是 `ts`.
* API 测试会覆盖服务中的各个代码路径，因此它们必须放在根路径下的 `test` 目录中。文件名应使用其所测试的服务资源名称，例如，如果 API 测试要测试的资源是 `books`，通常位于 `/books`，那么文件名必须是 `books.spec.ts` ，并且必须放在 `test` 目录中。

## 测试什么

* 应用在路由上的中间件（认证等），以确保路由按预期工作。
* 控制器逻辑，以确保路由执行我们预期的行为。

## 测试服务的 API

如前所述，API 测试将使用 Jest 和 supertest 完成。

为了说明开发者如何进行 API 测试，我们给出如下示例：

```tsx
import express from "express"
import { authMiddleware } from "../auth"
import db from "../db"

const app = express()

app.get('/books', async (req, res) => {
	let books: Books[];
	if(req.query.author) {
		books = await db.getFilteredBooks({ author: req.query.author })
	} else {
		books = await db.getBooks()
	}
  res.json(books)
})

app.post('/books', authMiddleware, async (req, res) => {
	await db.insertBook(req.body)
	res.status(200).end()
})
```

在示例中，我们看到同一个路由使用了不同的 HTTP 方法：GET 和 POST。两个端点都指向同一个资源 books，因此必须创建一个名为 `books.spec.ts` 的文件，必须在 `test` 目录下放置它们的测试。

所有路由以及不同的执行流程都必须被充分测试。开发者必须为这些端点测试以下情况：

* 请求所有 books 可正常工作，返回 200 和全部 books 列表。
* 请求某个指定作者的所有 books 可正常工作，返回 200 和该作者的全部 books 列表。
* 未认证地发布一本书会失败，返回 401 和一条错误消息。
* 已认证地发布一本书可正常工作，返回 200 并插入该书。

这些情况肯定会获得它们的 **它**s，以及这些 its 的期望必须至少包含 **期望的响应状态码** 以及 **响应体中预期的内容** （如果有的话）。

这些端点测试应这样编写：

```tsx
import db from '../db'
import app from '../express_app.ts'
// 我们只模拟外部依赖，例如数据库
jest.mock('../db')

const mockDb = db as jest.Mocked<typeof db>

const server = supertest(app.getApp())

// 这也可以写成 /books?
describe('when requesting the books resource', () => {
	let url: string
	let aBook: Book
	let anotherBook: Book
	beforeEach(() => {
		url = '/books'
		aBook = { title: 'aTitle', author: 'anAuthor' }
		anotherBook = { title: 'anotherTitle', author: 'anotherAuthor' }
	})
	
	describe('when querying the books without an author', () => {
		beforeEach(() => {
			mockDb.getBooks.mockResolvedValueOnce([aBook, anotherBook])
		})

		it('should respond with a 200 and all the books', () => {
			return server
	      .get(url)
	      .expect(200)
	      .then((response) => {
					expect(response.body).toEqual([aBook, anotherBook])
	      })
		})
	})
	
	describe('when querying the books with an author', () => {
		beforeEach(() => {
			mockDb.getFilteredBooks.mockResolvedValueOnce([anotherBook])
		})

		it('should respond with a 200 and all the books of an author', () => {
			return server
	      .get(url)
				.query({ author: 'anotherAuthor' })
	      .expect(200)
	      .then((response) => {
					expect(response.body).toEqual([anotherBook])
	      })
		})
	})
	
	describe('when posting a new book unauthenticated', () => {
		it('should respond with a 401 and an error saying that the user is unauthenticated', () => {
			return server
	      .post(url)
				.send(book)
	      .expect(401)
	      .then((response) => {
					expect(response.body).toEqual({ error: 'Unauthenticated' })
	      })
		})
	})
	
	describe('when posting a new book authenticated', () => {	
		it('should respond with a 200 and insert the book', () => {
			return server
	      .post('/books')
	      .set(createAuthHeaders('post', url))
				.send(aBook)
	      .expect(200)
	      .then(() => {
					// 检查书是否已插入
	        expect(db.insertBook).toHaveBeenCalledWith(aBook)
	      })
		})
	})
})
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.decentraland.org/contributor/contributor-zh/gong-xian-zhe-zhi-nan/testing-standards/testing-services-deprecated.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
