|
|
@ -0,0 +1,191 @@ |
|
|
|
|
|
|
|
*** |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
titre : "Écrire des tests unitaires" |
|
|
|
|
|
|
|
description: "Présentation des tests unitaires" |
|
|
|
|
|
|
|
balises : \['Ingénierie'] |
|
|
|
|
|
|
|
------------------------- |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Tests unitaires |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Tous les tests unitaires individuels sont indépendants les uns des autres. Nous n'utilisons aucun état partagé entre les tests. |
|
|
|
|
|
|
|
* L'environnement de test comprend`sakila`exemple de base de données et toute modification apportée à celle-ci par un test est annulée avant l'exécution d'autres tests. |
|
|
|
|
|
|
|
* Lors de l'exécution de tests unitaires, il essaie de se connecter au serveur MySQL exécuté sur`localhost:3306`avec nom d'utilisateur`root`et mot de passe`password`(qui peut être configuré) et s'il n'est pas trouvé, il utilisera`sqlite`comme solution de secours, donc aucune exigence d'un serveur SQL pour exécuter des tests. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Conditions préalables |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* MySQL est préférable - mais les tests peuvent également s'appuyer sur SQLite |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Installation |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
|
|
pnpm --filter=-nocodb install |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# add a .env file |
|
|
|
|
|
|
|
cp tests/unit/.env.sample tests/unit/.env |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# open .env file |
|
|
|
|
|
|
|
open tests/unit/.env |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Configurez les variables suivantes |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
> DB\_HOST : hôte |
|
|
|
|
|
|
|
> DB\_PORT : port |
|
|
|
|
|
|
|
> DB\_USER : nom d'utilisateur |
|
|
|
|
|
|
|
> DB\_PASSWORD : mot de passe |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Exécuter des tests |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```bash |
|
|
|
|
|
|
|
pnpm run test:unit |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Structure des dossiers |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Le dossier racine des tests unitaires est`packages/nocodb/tests/unit` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* `rest`Le dossier contient toutes les suites de tests pour les API restantes. |
|
|
|
|
|
|
|
* `model`Le dossier contient toutes les suites de tests pour les modèles. |
|
|
|
|
|
|
|
* `factory`Le dossier contient toutes les fonctions d’aide pour créer des données de test. |
|
|
|
|
|
|
|
* `init`Le dossier contient des fonctions d'assistance pour configurer l'environnement de test. |
|
|
|
|
|
|
|
* `index.test.ts`est le fichier racine de la suite de tests qui importe toutes les suites de tests. |
|
|
|
|
|
|
|
* `TestDbMngr.ts`est une classe d'assistance pour gérer les bases de données de test (c'est-à-dire la création, la suppression, etc.). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Modèle d'usine |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Utilisez des usines pour créer/mettre à jour/supprimer des données. Aucune donnée ne doit être directement créée/mise à jour/supprimée dans le test. |
|
|
|
|
|
|
|
* Lors de l'écriture d'une usine, assurez-vous qu'elle peut être utilisée avec le moins de paramètres possible et utilisez les valeurs par défaut pour les autres paramètres. |
|
|
|
|
|
|
|
* Utilisez des paramètres nommés pour les usines. |
|
|
|
|
|
|
|
```ts |
|
|
|
|
|
|
|
createUser({ email, password}) |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
* Utilisez un fichier par usine. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Procédure pas à pas pour l'écriture d'un test unitaire |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous allons créer un`Table`suite de tests à titre d'exemple. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Configurer le test |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous allons configurer`beforeEach`qui est appelé avant l’exécution de chaque test. Nous utiliserons`init`fonction de`nocodb/packages/nocodb/tests/unit/init/index.ts`, qui est une fonction d'assistance qui configure l'environnement de test (c'est-à-dire la réinitialisation de l'état, etc.). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
`init`fait les choses suivantes - |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
* Il initialise un`Noco`instance (réutilisée dans tous les tests). |
|
|
|
|
|
|
|
* Restaure`meta`et`sakila`base de données à son état initial. |
|
|
|
|
|
|
|
* Crée l'utilisateur root. |
|
|
|
|
|
|
|
* Retour`context`qui a`auth token`pour l'utilisateur créé, instance de serveur de nœud (`app`), et`dbConfig`. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous utiliserons`createProject`et`createProject`usines pour créer un projet et une table. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript |
|
|
|
|
|
|
|
let context; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async function () { |
|
|
|
|
|
|
|
context = await init(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
project = await createProject(context); |
|
|
|
|
|
|
|
table = await createTable(context, project); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Cas de test |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous utiliserons`it`fonction pour créer un scénario de test. Nous utiliserons`supertest`pour faire une requête au serveur. Nous utilisons`expect`(`chai`) pour affirmer la réponse. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript |
|
|
|
|
|
|
|
it('Get table list', async function () { |
|
|
|
|
|
|
|
const response = await request(context.app) |
|
|
|
|
|
|
|
.get(`/api/v1/db/meta/projects/${project.id}/tables`) |
|
|
|
|
|
|
|
.set('xc-auth', context.token) |
|
|
|
|
|
|
|
.send({}) |
|
|
|
|
|
|
|
.expect(200); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(response.body.list).to.be.an('array').not.empty; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
:::Info |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
We can also run individual test by using `.only`dans`describe`ou`it`fonction et l’exécution de la commande test. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
::: |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript |
|
|
|
|
|
|
|
it.only('Get table list', async () => { |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#### Intégration de la nouvelle suite de tests |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous créons un nouveau fichier`table.test.ts`dans`packages/nocodb/tests/unit/rest/tests`annuaire. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript |
|
|
|
|
|
|
|
import 'mocha'; |
|
|
|
|
|
|
|
import request from 'supertest'; |
|
|
|
|
|
|
|
import init from '../../init'; |
|
|
|
|
|
|
|
import { createTable, getAllTables } from '../../factory/table'; |
|
|
|
|
|
|
|
import { createProject } from '../../factory/project'; |
|
|
|
|
|
|
|
import { defaultColumns } from '../../factory/column'; |
|
|
|
|
|
|
|
import Model from '../../../../src/lib/models/Model'; |
|
|
|
|
|
|
|
import { expect } from 'chai'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tableTest() { |
|
|
|
|
|
|
|
let context; |
|
|
|
|
|
|
|
let project; |
|
|
|
|
|
|
|
let table; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async function () { |
|
|
|
|
|
|
|
context = await init(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
project = await createProject(context); |
|
|
|
|
|
|
|
table = await createTable(context, project); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Get table list', async function () { |
|
|
|
|
|
|
|
const response = await request(context.app) |
|
|
|
|
|
|
|
.get(`/api/v1/db/meta/projects/${project.id}/tables`) |
|
|
|
|
|
|
|
.set('xc-auth', context.token) |
|
|
|
|
|
|
|
.send({}) |
|
|
|
|
|
|
|
.expect(200); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(response.body.list).to.be.an('array').not.empty; |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function () { |
|
|
|
|
|
|
|
describe('Table', tableTests); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Nous pouvons alors importer le`Table`suite de tests pour`Rest`suite de tests dans`packages/nocodb/tests/unit/rest/index.test.ts`déposer(`Rest`la suite de tests est importée dans le fichier racine de la suite de tests qui est`packages/nocodb/tests/unit/index.test.ts`). |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
### Base de données d'échantillons d'ensemencement (Sakila) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```typescript |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function tableTest() { |
|
|
|
|
|
|
|
let context; |
|
|
|
|
|
|
|
let sakilaProject: Project; |
|
|
|
|
|
|
|
let customerTable: Model; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beforeEach(async function () { |
|
|
|
|
|
|
|
context = await init(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/******* Start : Seeding sample database **********/ |
|
|
|
|
|
|
|
sakilaProject = await createSakilaProject(context); |
|
|
|
|
|
|
|
/******* End : Seeding sample database **********/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
customerTable = await getTable({project: sakilaProject, name: 'customer'}) |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
it('Get table data list', async function () { |
|
|
|
|
|
|
|
const response = await request(context.app) |
|
|
|
|
|
|
|
.get(`/api/v1/db/data/noco/${sakilaProject.id}/${customerTable.id}`) |
|
|
|
|
|
|
|
.set('xc-auth', context.token) |
|
|
|
|
|
|
|
.send({}) |
|
|
|
|
|
|
|
.expect(200); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
expect(response.body.list[0]['FirstName']).to.equal('MARY'); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
``` |