Casos de prueba: RBAC (roles, permisos y catálogo)
Documenta los tests de los módulos role, role-permission, permission, permission-catalog-seed y module. Los specs de controladores y servicios usan mocks; los de repositorio y el seed usan MongoDB en memoria (mongodb-memory-server); los *.auth.spec.ts y *.permissions.spec.ts levantan una app Nest real con supertest para probar los guards a través del pipeline HTTP.
Specs fuente (bajo src/app/modules/):
role/controllers/role.controller.auth.spec.ts
role/controllers/role.controller.permissions.spec.ts
role/controllers/role.controller.spec.ts
role/services/role.service.spec.ts
role-permission/controllers/role-permission.controller.auth.spec.ts
role-permission/controllers/role-permission.controller.spec.ts
role-permission/services/role-permission.service.spec.ts
permission/controllers/permission.controller.spec.ts
permission/repositories/permission.repository.spec.ts
permission/services/permission.service.spec.ts
permission-catalog-seed/services/permission-catalog-seed.service.spec.ts
module/controllers/module.controller.spec.ts
module/migrations/catalog-clone-plan.spec.ts
module/repositories/module.repository.spec.ts
module/services/module.service.spec.ts
Resumen: 15 specs, 127 tests (role 25, role-permission 28, permission 28, permission-catalog-seed 14, module 32). Los describe.each se cuentan por fila.
Módulo role
role.controller.auth.spec.ts
RoleController: auth guard integration (bug fix)
Se usa el AuthGuard real (con JwtService y UserService mockeados) y se anula solo PermissionsGuard. Un describe.each recorre 5 rutas.
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns 401 Unauthorized without an x-api-key header (ejecutado para post /v1/roles/create, get /v1/roles/get-all, get /v1/roles/get-one/abc, patch /v1/roles/update/abc, delete /v1/roles/remove/abc) | Petición sin cabecera x-api-key a cada ruta | HTTP 401 en las 5 rutas (el @Auth() de clase protege todo el controlador) | RoleService, JwtService.verify, UserService.findByEmail, PermissionsGuard (permite todo) |
role.controller.permissions.spec.ts
RoleController: ACCESS_CONTROL permission guard integration
PermissionsGuard y Reflector reales; FakeAuthGuard inyecta tenantId y roleId; el resolver de permisos está mockeado.
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns 403 Forbidden for GET /get-all when ACCESS_CONTROL_READ is missing | GET /v1/roles/get-all sin permisos concedidos | HTTP 403 y findAll no se invoca | FakeAuthGuard, PermissionResolverService.resolve, RoleService.findAll |
returns 200 OK for GET /get-all when ACCESS_CONTROL_READ is granted | Mismo endpoint con ACCESS_CONTROL_READ concedido | HTTP 200 y findAll se invoca | FakeAuthGuard, PermissionResolverService.resolve, RoleService.findAll |
role.controller.spec.ts
RoleController / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should pass tenantId from user to service and return created role | Alta de rol con name y acronym | Llama create(dto, tenantId) y responde { message: 'role.created', data } | RoleService.create, AuthGuard y PermissionsGuard (permiten todo) |
RoleController / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should scope roles to the current user tenant | El servicio devuelve un rol | Llama findAll(tenantId) y responde role.findAll con results | RoleService.findAll |
should return message and empty array when tenant has no roles | El servicio devuelve [] | data.results es [] | RoleService.findAll |
RoleController / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and role when found | El rol existe | Llama findOne(id, lang) y responde role.findOne | RoleService.findOne |
should propagate NotFoundException when role not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RoleService.findOne |
RoleController / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and updated role | DTO { name: 'Admin Updated' } | Llama update(id, dto, lang) y responde role.updated | RoleService.update |
should propagate NotFoundException when role not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RoleService.update |
RoleController / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and removed role | El rol existe | Llama remove(id, lang) y responde role.deleted | RoleService.remove |
should propagate NotFoundException when role not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RoleService.remove |
role.service.spec.ts
RoleService / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should create and return a role | Alta con DTO y tenantId | Llama create(dto, tenantId) y devuelve el rol | RoleRepository.create |
RoleService / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return roles scoped to the given tenant | El repositorio devuelve roles del tenant | Usa findByTenantId(tenantId), nunca findAll, y devuelve la lista | RoleRepository.findByTenantId, RoleRepository.findAll |
should return an empty array when tenant has no roles | El tenant no tiene roles | Devuelve [] | RoleRepository.findByTenantId |
RoleService / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return a role when found | findById devuelve el rol | Llama findById(id) y lo devuelve | RoleRepository.findById |
should throw NotFoundException when role does not exist | findById devuelve null | NotFoundException | RoleRepository.findById |
RoleService / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should update and return the role | DTO { name: 'Admin Updated' } | Llama update(id, dto) y devuelve el rol actualizado | RoleRepository.update |
should throw NotFoundException when role does not exist | update devuelve null | NotFoundException | RoleRepository.update |
RoleService / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should remove and return the role | remove devuelve el rol | Llama remove(id) y lo devuelve | RoleRepository.remove |
should throw NotFoundException when role does not exist | remove devuelve null | NotFoundException | RoleRepository.remove |
Módulo role-permission
role-permission.controller.auth.spec.ts
RolePermissionController: auth guard integration (bug fix)
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns 401 Unauthorized without an x-api-key header (ejecutado para post /v1/role-permissions/create, get /v1/role-permissions/get-all, get /v1/role-permissions/get-one/abc, patch /v1/role-permissions/update/abc, delete /v1/role-permissions/remove/abc) | Petición sin x-api-key a cada ruta, con AuthGuard real | HTTP 401 en las 5 rutas | RolePermissionService, JwtService.verify, UserService.findByEmail, PermissionsGuard (permite todo) |
role-permission.controller.spec.ts
RolePermissionController / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and created role permission | Alta con name, acronym, roleId, permissions y tenantId | Llama create(dto) y responde { message: 'rolePermission.created', data } | RolePermissionService.create |
RolePermissionController / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should scope role permissions to the current user tenant | El servicio devuelve una lista | Llama findAll(tenantId) y responde rolePermission.findAll con results | RolePermissionService.findAll |
should return message and empty array when tenant has no role permissions | El servicio devuelve [] | data.results es [] | RolePermissionService.findAll |
RolePermissionController / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and role permission when found | El registro existe | Llama findOne(id, lang) y responde rolePermission.findOne | RolePermissionService.findOne |
should propagate NotFoundException when role permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RolePermissionService.findOne |
RolePermissionController / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and updated role permission | DTO { name: 'Admin Updated' } | Llama update(id, dto, lang) y responde rolePermission.updated | RolePermissionService.update |
should propagate NotFoundException when role permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RolePermissionService.update |
RolePermissionController / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and removed role permission | El registro existe | Llama remove(id, lang) y responde rolePermission.deleted | RolePermissionService.remove |
should propagate NotFoundException when role permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | RolePermissionService.remove |
role-permission.service.spec.ts
El servicio invalida la caché del PermissionResolverService cada vez que cambian los permisos de un rol.
RolePermissionService / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should create and return a role permission | Alta con DTO válido | Llama create(dto) y devuelve el registro | RolePermissionRepository.create |
invalidates the permission-resolver cache for the affected role (bugfix: role edits were not reflected until the 60s cache expired) | Alta correcta | Se llama invalidate(tenantId, roleId) del registro creado | RolePermissionRepository.create, PermissionResolverService.invalidate |
RolePermissionService / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return role permissions scoped to the given tenant | El repositorio devuelve registros del tenant | Usa findByTenantId(tenantId), nunca findAll | RolePermissionRepository.findByTenantId, RolePermissionRepository.findAll |
should return an empty array when tenant has no role permissions | Sin registros | Devuelve [] | RolePermissionRepository.findByTenantId |
RolePermissionService / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return a role permission when found | findById devuelve el registro | Llama findById(id) y lo devuelve | RolePermissionRepository.findById |
should throw NotFoundException when role permission does not exist | findById devuelve null | NotFoundException | RolePermissionRepository.findById |
RolePermissionService / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should update and return the role permission | DTO { name: 'Admin Updated' } | Llama update(id, dto) y devuelve el registro | RolePermissionRepository.update |
should throw NotFoundException when role permission does not exist | update devuelve null | NotFoundException | RolePermissionRepository.update |
invalidates the permission-resolver cache for the affected role so the new grants apply immediately | Actualización correcta | Se llama invalidate(tenantId, roleId) con los datos del registro actualizado | RolePermissionRepository.update, PermissionResolverService.invalidate |
does not touch the permission-resolver cache when the role permission does not exist | update devuelve null | NotFoundException y invalidate no se llama | RolePermissionRepository.update, PermissionResolverService.invalidate |
RolePermissionService / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should remove and return the role permission | remove devuelve el registro | Llama remove(id) y lo devuelve | RolePermissionRepository.remove |
should throw NotFoundException when role permission does not exist | remove devuelve null | NotFoundException | RolePermissionRepository.remove |
invalidates the permission-resolver cache for the affected role so a revoked permission stops applying immediately | Borrado correcto | Se llama invalidate(tenantId, roleId) | RolePermissionRepository.remove, PermissionResolverService.invalidate |
does not touch the permission-resolver cache when the role permission does not exist | remove devuelve null | NotFoundException y invalidate no se llama | RolePermissionRepository.remove, PermissionResolverService.invalidate |
Módulo permission
permission.controller.spec.ts
PermissionController / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should pass the dto to the service and return the created permission | Alta con name, acronym, moduleId | Llama create(dto) y responde { message: 'permission.created', data } | PermissionService.create, AuthGuard y PermissionsGuard (permiten todo) |
PermissionController / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return every permission in the global catalog | El servicio devuelve un permiso | Llama findAll() sin argumentos (catálogo global) y responde permission.findAll | PermissionService.findAll |
should return message and empty array when there are no permissions | El servicio devuelve [] | data.results es [] | PermissionService.findAll |
PermissionController / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and permission when found | El permiso existe | Llama findOne(id, lang) y responde permission.findOne | PermissionService.findOne |
should propagate NotFoundException when permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | PermissionService.findOne |
PermissionController / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and updated permission | DTO { name: 'Create Users Updated' } | Llama update(id, dto, lang) y responde permission.updated | PermissionService.update |
should propagate NotFoundException when permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | PermissionService.update |
PermissionController / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and removed permission | El permiso existe | Llama remove(id, lang) y responde permission.deleted | PermissionService.remove |
should propagate NotFoundException when permission not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | PermissionService.remove |
permission.repository.spec.ts
Integración con MongoDB en memoria; se esperan los índices (createIndexes) antes de empezar para que el índice único de acronym exista.
PermissionRepository: global catalog
| Test | Escenario | Resultado esperado | Mocks |
|---|
creates a permission without any tenant scoping | Alta de CRM_CREATE | El documento no tiene tenantId | Mongo real |
rejects a duplicate acronym globally (unique index) | Se crea dos veces DUP | La segunda creación lanza error (índice único) | Mongo real |
findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns every permission in the global catalog | Dos permisos creados | Devuelve los 2 | Mongo real |
findById
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns the permission by identifier | Permiso existente | Lo devuelve por identifier | Mongo real |
returns null when the identifier does not exist | Identifier inexistente | Devuelve null | Mongo real |
findByModuleId
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns only permissions belonging to the given module | Permisos de dos módulos distintos | Solo devuelve el del módulo pedido | Mongo real |
update
| Test | Escenario | Resultado esperado | Mocks |
|---|
updates the permission by identifier | Cambia el nombre a Edited | Devuelve el permiso con el nombre nuevo | Mongo real |
returns null when the identifier does not exist | Actualiza un identifier inexistente | Devuelve null | Mongo real |
remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
removes the permission by identifier | Permiso existente | Devuelve el permiso y findById posterior devuelve null | Mongo real |
returns null when the identifier does not exist | Borra un identifier inexistente | Devuelve null | Mongo real |
permission.service.spec.ts
PermissionService / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should create a permission without any tenant scoping | Alta con DTO válido | Llama create(dto) y devuelve el permiso | PermissionRepository.create |
PermissionService / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return every permission in the global catalog | El repositorio devuelve un permiso | Llama findAll() sin argumentos y devuelve la lista | PermissionRepository.findAll |
should return an empty array when there are no permissions | Sin permisos | Devuelve [] | PermissionRepository.findAll |
PermissionService / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return a permission when found | findById devuelve el permiso | Llama findById(id) y lo devuelve | PermissionRepository.findById |
should throw NotFoundException when permission does not exist | findById devuelve null | NotFoundException | PermissionRepository.findById |
PermissionService / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should update and return the permission | DTO { name: 'Create Users Updated' } | Llama update(id, dto) y devuelve el permiso | PermissionRepository.update |
should throw NotFoundException when permission does not exist | update devuelve null | NotFoundException | PermissionRepository.update |
PermissionService / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should remove and return the permission | remove devuelve el permiso | Llama remove(id) y lo devuelve | PermissionRepository.remove |
should throw NotFoundException when permission does not exist | remove devuelve null | NotFoundException | PermissionRepository.remove |
Módulo permission-catalog-seed
permission-catalog-seed.service.spec.ts
Integración con MongoDB en memoria y los modelos reales de Module, Permission, Tenant, Role y RolePermission. Se restaura process.env.MIGRATION_DB_DATA tras cada test.
PermissionCatalogSeedService / seedGlobalCatalog: idempotency
| Test | Escenario | Resultado esperado | Mocks |
|---|
inserts every catalog module and permission on first call | Primera ejecución sobre base vacía | Existen tantos módulos y permisos como CATALOG_MODULES y CATALOG_PERMISSIONS | Mongo real |
does not duplicate rows when called twice | Se ejecuta dos veces | Los conteos se mantienen iguales | Mongo real |
never touches updatedAt on an already-existing row when called again | Re-seed tras 5 ms | El updatedAt del módulo USER no cambia | Mongo real |
links each permission to its own module via moduleId | Tras el seed | USER_CREATE apunta al _id del módulo USER | Mongo real |
seedDefaultRoleGrantsForTenant: default role grants
| Test | Escenario | Resultado esperado | Mocks |
|---|
grants ADMIN every catalog permission acronym and AGENT only the agent-facing subset | Seed del catálogo y de los grants del tenant A | Se crean los roles ADMIN (Administrador) y AGENT (Agente); ADMIN recibe todos los acrónimos del catálogo y AGENT solo los de módulos de agente que no son adminOnly; TICKET_UNLOCK_ANY y TICKET_FILTER_BY_AGENT no llegan a AGENT y TICKET_VIEW_AGENT_AVATAR sí | Mongo real |
does not duplicate roles or grants when called twice for the same tenant | Se ejecuta dos veces para el mismo tenant | Quedan 2 roles y 2 grants | Mongo real |
leaves a tenant's own pre-existing ADMIN role untouched (name, no duplicate) and still grants it DEFAULT_ADMIN_GRANT | El tenant ya tiene un rol ADMIN personalizado | No se duplica ni se cambia su nombre/descripción, y recibe el grant por defecto con todos los permisos | Mongo real |
never restores or adds back into a manually-trimmed DEFAULT_ADMIN_GRANT on a later call | Se recorta manualmente el grant ADMIN a 1 permiso y se vuelve a ejecutar el seed | El grant sigue con 1 solo permiso (no se restaura) | Mongo real |
recovers via refetch when Role.create() loses a duplicate-key race | Role.create falla con error E11000 porque otra llamada insertó el rol antes | Se recupera releyendo el rol: queda 1 solo ADMIN y su grant con todos los permisos | jest.spyOn(roleModel, 'create') |
seeding tenant B's default roles/grants never touches tenant A's | Se siembra el tenant B después del A | Roles y grants del tenant A quedan idénticos; el tenant B tiene 2 roles | Mongo real |
every tenant's grant only ever references permissions from the single global catalog, regardless of seeding order | Se siembra B antes que A | Todos los permisos del grant ADMIN del tenant A pertenecen al catálogo global | Mongo real |
onModuleInit: MIGRATION_DB_DATA gate
| Test | Escenario | Resultado esperado | Mocks |
|---|
does nothing (no query at all) when the flag is not the string "true" | MIGRATION_DB_DATA = 'false' | tenantModel.find no se llama | jest.spyOn(tenantModel, 'find') |
does nothing when the flag is unset | Variable de entorno eliminada | tenantModel.find no se llama | jest.spyOn(tenantModel, 'find') |
seeds the global catalog once and default role grants for every existing tenant when the flag is "true" | MIGRATION_DB_DATA = 'true' y dos tenants existentes | Se siembra el catálogo global y cada tenant recibe 2 roles | Mongo real |
Módulo module
module.controller.spec.ts
ModuleController / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should pass the dto to the service and return the created module | Alta { name: 'CRM', acronym: 'CRM' } | Llama create(dto) y responde { message: 'module.created', data } | ModuleService.create, AuthGuard y PermissionsGuard (permiten todo) |
ModuleController / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return every module in the global catalog | El servicio devuelve un módulo | Llama findAll() sin argumentos y responde module.findAll | ModuleService.findAll |
should return message and empty array when there are no modules | El servicio devuelve [] | data.results es [] | ModuleService.findAll |
ModuleController / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and module when found | El módulo existe | Llama findOne(id, lang) y responde module.findOne | ModuleService.findOne |
should propagate NotFoundException when module not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | ModuleService.findOne |
ModuleController / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and updated module | DTO { name: 'CRM Updated' } | Llama update(id, dto, lang) y responde module.updated | ModuleService.update |
should propagate NotFoundException when module not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | ModuleService.update |
ModuleController / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return message and removed module | El módulo existe | Llama remove(id, lang) y responde module.deleted | ModuleService.remove |
should propagate NotFoundException when module not found | El servicio rechaza con NotFoundException | Se propaga NotFoundException | ModuleService.remove |
catalog-clone-plan.spec.ts
Pruebas de funciones puras de la migración que clona el catálogo legacy a un tenant; no usan mocks.
buildClonePlan
| Test | Escenario | Resultado esperado | Mocks |
|---|
clones every legacy module and permission into new tenant-owned docs on first run | 2 módulos y 3 permisos legacy, sin clones existentes | Planea insertar 2 módulos (con el tenantId) y 3 permisos, cada permiso apunta a un módulo clonado, y los mapas de reasignación tienen 2 y 3 entradas | Ninguno |
is idempotent — re-running with the already-cloned catalog produces zero inserts | Se vuelve a planificar con los clones de la primera ejecución | 0 inserciones y los mapas de reasignación resuelven a los mismos ids ya clonados | Ninguno |
skips a permission whose legacy moduleId is not in the given module set | Permiso huérfano cuyo moduleId no está entre los módulos | No se inserta ningún permiso ni se crea entrada de reasignación | Ninguno |
rewireRolePermissionIds
| Test | Escenario | Resultado esperado | Mocks |
|---|
maps every legacy permission id to its cloned counterpart, preserving order | Ids legacy [B, A] con mapa de reasignación | Devuelve [clonedB, clonedA] conservando el orden | Ninguno |
drops ids that have no entry in the rewire map | Un id legacy sin entrada en el mapa | El id huérfano se descarta y devuelve solo [clonedA] | Ninguno |
module.repository.spec.ts
Integración con MongoDB en memoria; se esperan los índices antes de empezar.
ModuleRepository: global catalog
| Test | Escenario | Resultado esperado | Mocks |
|---|
creates a module without any tenant scoping | Alta del módulo CRM | El documento no tiene tenantId | Mongo real |
rejects a duplicate acronym globally (unique index) | Se crea dos veces DUP | La segunda creación lanza error | Mongo real |
findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns every module in the global catalog | Dos módulos creados | Devuelve los 2 | Mongo real |
findById
| Test | Escenario | Resultado esperado | Mocks |
|---|
returns the module by identifier | Módulo existente | Lo devuelve por identifier | Mongo real |
returns null when the identifier does not exist | Identifier inexistente | Devuelve null | Mongo real |
update
| Test | Escenario | Resultado esperado | Mocks |
|---|
updates the module by identifier | Cambia el nombre a Edited | Devuelve el módulo con el nombre nuevo | Mongo real |
returns null when the identifier does not exist | Actualiza un identifier inexistente | Devuelve null | Mongo real |
remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
removes the module by identifier | Módulo existente | Devuelve el módulo y findById posterior devuelve null | Mongo real |
returns null when the identifier does not exist | Borra un identifier inexistente | Devuelve null | Mongo real |
module.service.spec.ts
ModuleService / create
| Test | Escenario | Resultado esperado | Mocks |
|---|
should create a module without any tenant scoping | Alta con DTO válido | Llama create(dto) y devuelve el módulo | ModuleRepository.create |
ModuleService / findAll
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return every module in the global catalog | El repositorio devuelve un módulo | Llama findAll() sin argumentos y devuelve la lista | ModuleRepository.findAll |
should return an empty array when there are no modules | Sin módulos | Devuelve [] | ModuleRepository.findAll |
ModuleService / findOne
| Test | Escenario | Resultado esperado | Mocks |
|---|
should return a module when found | findById devuelve el módulo | Llama findById(id) y lo devuelve | ModuleRepository.findById |
should throw NotFoundException when module does not exist | findById devuelve null | NotFoundException | ModuleRepository.findById |
ModuleService / update
| Test | Escenario | Resultado esperado | Mocks |
|---|
should update and return the module | DTO { name: 'CRM Updated' } | Llama update(id, dto) y devuelve el módulo | ModuleRepository.update |
should throw NotFoundException when module does not exist | update devuelve null | NotFoundException | ModuleRepository.update |
ModuleService / remove
| Test | Escenario | Resultado esperado | Mocks |
|---|
should remove and return the module | remove devuelve el módulo | Llama remove(id) y lo devuelve | ModuleRepository.remove |
should throw NotFoundException when module does not exist | remove devuelve null | NotFoundException | ModuleRepository.remove |